blob: 6cec56c3c83b53448331963ec38c94523f126679 [file] [log] [blame]
Brad Ebinger4dc095a2018-04-03 15:17:52 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.phone;
18
Hall Liud892bec2018-11-30 14:51:45 -080019import android.os.Binder;
20import android.os.Process;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070021import android.os.RemoteException;
22import android.os.ShellCommand;
sqian2fff4a32018-11-05 14:18:37 -080023import android.os.UserHandle;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070024import android.telephony.SubscriptionManager;
25import android.util.Log;
26
27import com.android.internal.telephony.ITelephony;
28
29import java.io.PrintWriter;
30
31/**
32 * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
33 * permission checks have been done before onCommand was called. Make sure any commands processed
34 * here also contain the appropriate permissions checks.
35 */
36
37public class TelephonyShellCommand extends ShellCommand {
38
39 private static final String LOG_TAG = "TelephonyShellCommand";
40 // Don't commit with this true.
41 private static final boolean VDBG = true;
Brad Ebinger0aa2f242018-04-12 09:49:23 -070042 private static final int DEFAULT_PHONE_ID = 0;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070043
44 private static final String IMS_SUBCOMMAND = "ims";
sqian2fff4a32018-11-05 14:18:37 -080045 private static final String SMS_SUBCOMMAND = "sms";
Hall Liud892bec2018-11-30 14:51:45 -080046 private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
47
Brad Ebinger4dc095a2018-04-03 15:17:52 -070048 private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service";
49 private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
50 private static final String IMS_ENABLE = "enable";
51 private static final String IMS_DISABLE = "disable";
52
sqian2fff4a32018-11-05 14:18:37 -080053 private static final String SMS_GET_APPS = "get-apps";
54 private static final String SMS_GET_DEFAULT_APP = "get-default-app";
55 private static final String SMS_SET_DEFAULT_APP = "set-default-app";
56
Hall Liud892bec2018-11-30 14:51:45 -080057 private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
Hall Liuca5af3a2018-12-04 16:58:23 -080058 private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
Hall Liud892bec2018-11-30 14:51:45 -080059
Brad Ebinger4dc095a2018-04-03 15:17:52 -070060 // Take advantage of existing methods that already contain permissions checks when possible.
61 private final ITelephony mInterface;
62
63 public TelephonyShellCommand(ITelephony binder) {
64 mInterface = binder;
65 }
66
67 @Override
68 public int onCommand(String cmd) {
69 if (cmd == null) {
70 return handleDefaultCommands(null);
71 }
72
73 switch (cmd) {
74 case IMS_SUBCOMMAND: {
75 return handleImsCommand();
76 }
sqian2fff4a32018-11-05 14:18:37 -080077 case SMS_SUBCOMMAND: {
78 return handleSmsCommand();
79 }
Hall Liud892bec2018-11-30 14:51:45 -080080 case NUMBER_VERIFICATION_SUBCOMMAND:
81 return handleNumberVerificationCommand();
Brad Ebinger4dc095a2018-04-03 15:17:52 -070082 default: {
83 return handleDefaultCommands(cmd);
84 }
85 }
86 }
87
88 @Override
89 public void onHelp() {
90 PrintWriter pw = getOutPrintWriter();
91 pw.println("Telephony Commands:");
92 pw.println(" help");
93 pw.println(" Print this help text.");
94 pw.println(" ims");
95 pw.println(" IMS Commands.");
sqian2fff4a32018-11-05 14:18:37 -080096 pw.println(" sms");
97 pw.println(" SMS Commands.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -070098 onHelpIms();
sqian2fff4a32018-11-05 14:18:37 -080099 onHelpSms();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700100 }
101
102 private void onHelpIms() {
103 PrintWriter pw = getOutPrintWriter();
104 pw.println("IMS Commands:");
105 pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d) PACKAGE_NAME");
106 pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound");
107 pw.println(" ImsService. Options are:");
108 pw.println(" -s: the slot ID that the ImsService should be bound for. If no option");
109 pw.println(" is specified, it will choose the default voice SIM slot.");
110 pw.println(" -c: Override the ImsService defined in the carrier configuration.");
111 pw.println(" -d: Override the ImsService defined in the device overlay.");
112 pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]");
113 pw.println(" Gets the package name of the currently defined ImsService.");
114 pw.println(" Options are:");
115 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
116 pw.println(" is specified, it will choose the default voice SIM slot.");
117 pw.println(" -c: The ImsService defined as the carrier configured ImsService.");
118 pw.println(" -c: The ImsService defined as the device default ImsService.");
119 pw.println(" ims enable [-s SLOT_ID]");
120 pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot");
121 pw.println(" if none is specified.");
122 pw.println(" ims disable [-s SLOT_ID]");
123 pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM");
124 pw.println(" slot if none is specified.");
125 }
126
sqian2fff4a32018-11-05 14:18:37 -0800127 private void onHelpSms() {
128 PrintWriter pw = getOutPrintWriter();
129 pw.println("SMS Commands:");
130 pw.println(" sms get-apps [--user USER_ID]");
131 pw.println(" Print all SMS apps on a user.");
132 pw.println(" sms get-default-app [--user USER_ID]");
133 pw.println(" Get the default SMS app.");
134 pw.println(" sms set-default-app [--user USER_ID] PACKAGE_NAME");
135 pw.println(" Set PACKAGE_NAME as the default SMS app.");
136 }
137
Hall Liud892bec2018-11-30 14:51:45 -0800138
139 private void onHelpNumberVerification() {
140 PrintWriter pw = getOutPrintWriter();
141 pw.println("Number verification commands");
142 pw.println(" numverify override-package PACKAGE_NAME;");
143 pw.println(" Set the authorized package for number verification.");
144 pw.println(" Leave the package name blank to reset.");
Hall Liuca5af3a2018-12-04 16:58:23 -0800145 pw.println(" numverify fake-call NUMBER;");
146 pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be");
147 pw.println(" 1 if the call would have been intercepted, 0 otherwise.");
Hall Liud892bec2018-11-30 14:51:45 -0800148 }
149
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700150 private int handleImsCommand() {
151 String arg = getNextArg();
152 if (arg == null) {
153 onHelpIms();
154 return 0;
155 }
156
157 switch (arg) {
158 case IMS_SET_CARRIER_SERVICE: {
159 return handleImsSetServiceCommand();
160 }
161 case IMS_GET_CARRIER_SERVICE: {
162 return handleImsGetServiceCommand();
163 }
164 case IMS_ENABLE: {
165 return handleEnableIms();
166 }
167 case IMS_DISABLE: {
168 return handleDisableIms();
169 }
170 }
171
172 return -1;
173 }
174
Hall Liud892bec2018-11-30 14:51:45 -0800175 private int handleNumberVerificationCommand() {
176 String arg = getNextArg();
177 if (arg == null) {
178 onHelpNumberVerification();
179 return 0;
180 }
181
Hall Liuca5af3a2018-12-04 16:58:23 -0800182 if (!checkShellUid()) {
183 return -1;
184 }
185
Hall Liud892bec2018-11-30 14:51:45 -0800186 switch (arg) {
187 case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
Hall Liud892bec2018-11-30 14:51:45 -0800188 NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
189 return 0;
190 }
Hall Liuca5af3a2018-12-04 16:58:23 -0800191 case NUMBER_VERIFICATION_FAKE_CALL: {
192 boolean val = NumberVerificationManager.getInstance()
193 .checkIncomingCall(getNextArg());
194 getOutPrintWriter().println(val ? "1" : "0");
195 return 0;
196 }
Hall Liud892bec2018-11-30 14:51:45 -0800197 }
198
199 return -1;
200 }
201
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700202 // ims set-ims-service
203 private int handleImsSetServiceCommand() {
204 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700205 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700206 Boolean isCarrierService = null;
207
208 String opt;
209 while ((opt = getNextOption()) != null) {
210 switch (opt) {
211 case "-s": {
212 try {
213 slotId = Integer.parseInt(getNextArgRequired());
214 } catch (NumberFormatException e) {
215 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
216 return -1;
217 }
218 break;
219 }
220 case "-c": {
221 isCarrierService = true;
222 break;
223 }
224 case "-d": {
225 isCarrierService = false;
226 break;
227 }
228 }
229 }
230 // Mandatory param, either -c or -d
231 if (isCarrierService == null) {
232 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
233 return -1;
234 }
235
236 String packageName = getNextArg();
237
238 try {
239 if (packageName == null) {
240 packageName = "";
241 }
242 boolean result = mInterface.setImsService(slotId, isCarrierService, packageName);
243 if (VDBG) {
244 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
245 + (isCarrierService ? "-c " : "-d ") + packageName + ", result=" + result);
246 }
247 getOutPrintWriter().println(result);
248 } catch (RemoteException e) {
249 Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
250 + (isCarrierService ? "-c " : "-d ") + packageName + ", error"
251 + e.getMessage());
252 errPw.println("Exception: " + e.getMessage());
253 return -1;
254 }
255 return 0;
256 }
257
258 // ims get-ims-service
259 private int handleImsGetServiceCommand() {
260 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700261 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700262 Boolean isCarrierService = null;
263
264 String opt;
265 while ((opt = getNextOption()) != null) {
266 switch (opt) {
267 case "-s": {
268 try {
269 slotId = Integer.parseInt(getNextArgRequired());
270 } catch (NumberFormatException e) {
271 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
272 return -1;
273 }
274 break;
275 }
276 case "-c": {
277 isCarrierService = true;
278 break;
279 }
280 case "-d": {
281 isCarrierService = false;
282 break;
283 }
284 }
285 }
286 // Mandatory param, either -c or -d
287 if (isCarrierService == null) {
288 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
289 return -1;
290 }
291
292 String result;
293 try {
294 result = mInterface.getImsService(slotId, isCarrierService);
295 } catch (RemoteException e) {
296 return -1;
297 }
298 if (VDBG) {
299 Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
300 + (isCarrierService ? "-c " : "-d ") + ", returned: " + result);
301 }
302 getOutPrintWriter().println(result);
303 return 0;
304 }
305
306 private int handleEnableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700307 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700308 String opt;
309 while ((opt = getNextOption()) != null) {
310 switch (opt) {
311 case "-s": {
312 try {
313 slotId = Integer.parseInt(getNextArgRequired());
314 } catch (NumberFormatException e) {
315 getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID.");
316 return -1;
317 }
318 break;
319 }
320 }
321 }
322 try {
323 mInterface.enableIms(slotId);
324 } catch (RemoteException e) {
325 return -1;
326 }
327 if (VDBG) {
328 Log.v(LOG_TAG, "ims enable -s " + slotId);
329 }
330 return 0;
331 }
332
333 private int handleDisableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700334 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700335 String opt;
336 while ((opt = getNextOption()) != null) {
337 switch (opt) {
338 case "-s": {
339 try {
340 slotId = Integer.parseInt(getNextArgRequired());
341 } catch (NumberFormatException e) {
342 getErrPrintWriter().println(
343 "ims disable requires an integer as a SLOT_ID.");
344 return -1;
345 }
346 break;
347 }
348 }
349 }
350 try {
351 mInterface.disableIms(slotId);
352 } catch (RemoteException e) {
353 return -1;
354 }
355 if (VDBG) {
356 Log.v(LOG_TAG, "ims disable -s " + slotId);
357 }
358 return 0;
359 }
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700360
361 private int getDefaultSlot() {
362 int slotId = SubscriptionManager.getDefaultVoicePhoneId();
363 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
364 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
365 // If there is no default, default to slot 0.
366 slotId = DEFAULT_PHONE_ID;
367 }
368 return slotId;
369 }
sqian2fff4a32018-11-05 14:18:37 -0800370
371 private int handleSmsCommand() {
372 String arg = getNextArg();
373 if (arg == null) {
374 onHelpSms();
375 return 0;
376 }
377
378 try {
379 switch (arg) {
380 case SMS_GET_APPS: {
381 return handleSmsGetApps();
382 }
383 case SMS_GET_DEFAULT_APP: {
384 return handleSmsGetDefaultApp();
385 }
386 case SMS_SET_DEFAULT_APP: {
387 return handleSmsSetDefaultApp();
388 }
389 default:
390 getErrPrintWriter().println("Unknown command " + arg);
391 }
392 } catch (RemoteException e) {
393 getErrPrintWriter().println("RemoteException: " + e.getMessage());
394 }
395
396 return -1;
397 }
398
399 private int maybeParseUserIdArg() {
400 int userId = UserHandle.USER_SYSTEM;
401 String opt;
402 while ((opt = getNextOption()) != null) {
403 switch (opt) {
404 case "--user": {
405 try {
406 userId = Integer.parseInt(getNextArgRequired());
407 } catch (NumberFormatException e) {
408 getErrPrintWriter().println("Invalid user ID for --user");
409 return -1;
410 }
411 break;
412 }
413 }
414 }
415 return userId;
416 }
417
418 private int handleSmsGetApps() throws RemoteException {
419 final int userId = maybeParseUserIdArg();
420 if (userId < 0) {
421 return -1;
422 }
423
424 for (String packageName : mInterface.getSmsApps(userId)) {
425 getOutPrintWriter().println(packageName);
426 }
427 return 0;
428 }
429
430 private int handleSmsGetDefaultApp() throws RemoteException {
431 final int userId = maybeParseUserIdArg();
432 if (userId < 0) {
433 return -1;
434 }
435
436 getOutPrintWriter().println(mInterface.getDefaultSmsApp(userId));
437 return 0;
438 }
439
440 private int handleSmsSetDefaultApp() throws RemoteException {
441 final int userId = maybeParseUserIdArg();
442 if (userId < 0) {
443 return -1;
444 }
445
446 String packageName = getNextArgRequired();
447 mInterface.setDefaultSmsApp(userId, packageName);
448 getOutPrintWriter().println("SMS app set to " + mInterface.getDefaultSmsApp(userId));
449 return 0;
450 }
Hall Liud892bec2018-11-30 14:51:45 -0800451
452 private boolean checkShellUid() {
453 return Binder.getCallingUid() == Process.SHELL_UID;
454 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700455}