blob: f7ffa7a32b43adb6db00b92322216a8ae7c831e4 [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;
23import android.telephony.SubscriptionManager;
sqianf4ca7ed2019-01-15 18:32:07 -080024import android.telephony.emergency.EmergencyNumber;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070025import android.util.Log;
26
27import com.android.internal.telephony.ITelephony;
sqianf4ca7ed2019-01-15 18:32:07 -080028import com.android.internal.telephony.emergency.EmergencyNumberTracker;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070029
30import java.io.PrintWriter;
sqianf4ca7ed2019-01-15 18:32:07 -080031import java.util.ArrayList;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070032
33/**
34 * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
35 * permission checks have been done before onCommand was called. Make sure any commands processed
36 * here also contain the appropriate permissions checks.
37 */
38
39public class TelephonyShellCommand extends ShellCommand {
40
41 private static final String LOG_TAG = "TelephonyShellCommand";
42 // Don't commit with this true.
43 private static final boolean VDBG = true;
Brad Ebinger0aa2f242018-04-12 09:49:23 -070044 private static final int DEFAULT_PHONE_ID = 0;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070045
46 private static final String IMS_SUBCOMMAND = "ims";
Hall Liud892bec2018-11-30 14:51:45 -080047 private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
sqianf4ca7ed2019-01-15 18:32:07 -080048 private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
Hall Liud892bec2018-11-30 14:51:45 -080049
Brad Ebinger4dc095a2018-04-03 15:17:52 -070050 private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service";
51 private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
52 private static final String IMS_ENABLE = "enable";
53 private static final String IMS_DISABLE = "disable";
54
Hall Liud892bec2018-11-30 14:51:45 -080055 private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
Hall Liuca5af3a2018-12-04 16:58:23 -080056 private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
Hall Liud892bec2018-11-30 14:51:45 -080057
Brad Ebinger4dc095a2018-04-03 15:17:52 -070058 // Take advantage of existing methods that already contain permissions checks when possible.
59 private final ITelephony mInterface;
60
61 public TelephonyShellCommand(ITelephony binder) {
62 mInterface = binder;
63 }
64
65 @Override
66 public int onCommand(String cmd) {
67 if (cmd == null) {
68 return handleDefaultCommands(null);
69 }
70
71 switch (cmd) {
72 case IMS_SUBCOMMAND: {
73 return handleImsCommand();
74 }
Hall Liud892bec2018-11-30 14:51:45 -080075 case NUMBER_VERIFICATION_SUBCOMMAND:
76 return handleNumberVerificationCommand();
sqianf4ca7ed2019-01-15 18:32:07 -080077 case EMERGENCY_NUMBER_TEST_MODE:
78 return handleEmergencyNumberTestModeCommand();
Brad Ebinger4dc095a2018-04-03 15:17:52 -070079 default: {
80 return handleDefaultCommands(cmd);
81 }
82 }
83 }
84
85 @Override
86 public void onHelp() {
87 PrintWriter pw = getOutPrintWriter();
88 pw.println("Telephony Commands:");
89 pw.println(" help");
90 pw.println(" Print this help text.");
91 pw.println(" ims");
92 pw.println(" IMS Commands.");
sqianf4ca7ed2019-01-15 18:32:07 -080093 pw.println(" emergency-number-test-mode");
94 pw.println(" Emergency Number Test Mode Commands.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -070095 onHelpIms();
sqianf4ca7ed2019-01-15 18:32:07 -080096 onHelpEmergencyNumber();
Brad Ebinger4dc095a2018-04-03 15:17:52 -070097 }
98
99 private void onHelpIms() {
100 PrintWriter pw = getOutPrintWriter();
101 pw.println("IMS Commands:");
102 pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d) PACKAGE_NAME");
103 pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound");
104 pw.println(" ImsService. Options are:");
105 pw.println(" -s: the slot ID that the ImsService should be bound for. If no option");
106 pw.println(" is specified, it will choose the default voice SIM slot.");
107 pw.println(" -c: Override the ImsService defined in the carrier configuration.");
108 pw.println(" -d: Override the ImsService defined in the device overlay.");
109 pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]");
110 pw.println(" Gets the package name of the currently defined ImsService.");
111 pw.println(" Options are:");
112 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
113 pw.println(" is specified, it will choose the default voice SIM slot.");
114 pw.println(" -c: The ImsService defined as the carrier configured ImsService.");
115 pw.println(" -c: The ImsService defined as the device default ImsService.");
116 pw.println(" ims enable [-s SLOT_ID]");
117 pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot");
118 pw.println(" if none is specified.");
119 pw.println(" ims disable [-s SLOT_ID]");
120 pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM");
121 pw.println(" slot if none is specified.");
122 }
123
Hall Liud892bec2018-11-30 14:51:45 -0800124 private void onHelpNumberVerification() {
125 PrintWriter pw = getOutPrintWriter();
126 pw.println("Number verification commands");
127 pw.println(" numverify override-package PACKAGE_NAME;");
128 pw.println(" Set the authorized package for number verification.");
129 pw.println(" Leave the package name blank to reset.");
Hall Liuca5af3a2018-12-04 16:58:23 -0800130 pw.println(" numverify fake-call NUMBER;");
131 pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be");
132 pw.println(" 1 if the call would have been intercepted, 0 otherwise.");
Hall Liud892bec2018-11-30 14:51:45 -0800133 }
134
sqianf4ca7ed2019-01-15 18:32:07 -0800135 private void onHelpEmergencyNumber() {
136 PrintWriter pw = getOutPrintWriter();
137 pw.println("Emergency Number Test Mode Commands:");
138 pw.println(" emergency-number-test-mode ");
139 pw.println(" Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
140 + " the test mode");
141 pw.println(" -a <emergency number address>: add an emergency number address for the"
sqian6321e6d2019-03-14 19:45:39 -0700142 + " test mode, only allows '0'-'9', '*', '#' or '+'.");
sqianf4ca7ed2019-01-15 18:32:07 -0800143 pw.println(" -c: clear the emergency number list in the test mode.");
144 pw.println(" -r <emergency number address>: remove an existing emergency number"
sqian6321e6d2019-03-14 19:45:39 -0700145 + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'.");
sqianf4ca7ed2019-01-15 18:32:07 -0800146 pw.println(" -p: get the full emergency number list in the test mode.");
147 }
148
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700149 private int handleImsCommand() {
150 String arg = getNextArg();
151 if (arg == null) {
152 onHelpIms();
153 return 0;
154 }
155
156 switch (arg) {
157 case IMS_SET_CARRIER_SERVICE: {
158 return handleImsSetServiceCommand();
159 }
160 case IMS_GET_CARRIER_SERVICE: {
161 return handleImsGetServiceCommand();
162 }
163 case IMS_ENABLE: {
164 return handleEnableIms();
165 }
166 case IMS_DISABLE: {
167 return handleDisableIms();
168 }
169 }
170
171 return -1;
172 }
173
sqianf4ca7ed2019-01-15 18:32:07 -0800174 private int handleEmergencyNumberTestModeCommand() {
175 PrintWriter errPw = getErrPrintWriter();
176 String opt = getNextOption();
177 if (opt == null) {
178 onHelpEmergencyNumber();
179 return 0;
180 }
181
182 switch (opt) {
183 case "-a": {
184 String emergencyNumberCmd = getNextArgRequired();
185 if (emergencyNumberCmd == null
186 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian6321e6d2019-03-14 19:45:39 -0700187 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqianf4ca7ed2019-01-15 18:32:07 -0800188 + " to be specified after -a in the command ");
189 return -1;
190 }
191 try {
192 mInterface.updateEmergencyNumberListTestMode(
193 EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
194 new EmergencyNumber(emergencyNumberCmd, "", "",
195 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
196 new ArrayList<String>(),
197 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
198 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
199 } catch (RemoteException ex) {
200 Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
201 + ", error " + ex.getMessage());
202 errPw.println("Exception: " + ex.getMessage());
203 return -1;
204 }
205 break;
206 }
207 case "-c": {
208 try {
209 mInterface.updateEmergencyNumberListTestMode(
210 EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
211 } catch (RemoteException ex) {
212 Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
213 errPw.println("Exception: " + ex.getMessage());
214 return -1;
215 }
216 break;
217 }
218 case "-r": {
219 String emergencyNumberCmd = getNextArgRequired();
220 if (emergencyNumberCmd == null
221 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian6321e6d2019-03-14 19:45:39 -0700222 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqianf4ca7ed2019-01-15 18:32:07 -0800223 + " to be specified after -r in the command ");
224 return -1;
225 }
226 try {
227 mInterface.updateEmergencyNumberListTestMode(
228 EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
229 new EmergencyNumber(emergencyNumberCmd, "", "",
230 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
231 new ArrayList<String>(),
232 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
233 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
234 } catch (RemoteException ex) {
235 Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
236 + ", error " + ex.getMessage());
237 errPw.println("Exception: " + ex.getMessage());
238 return -1;
239 }
240 break;
241 }
242 case "-p": {
243 try {
244 getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
245 } catch (RemoteException ex) {
246 Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
247 errPw.println("Exception: " + ex.getMessage());
248 return -1;
249 }
250 break;
251 }
252 default:
253 onHelpEmergencyNumber();
254 break;
255 }
256 return 0;
257 }
258
Hall Liud892bec2018-11-30 14:51:45 -0800259 private int handleNumberVerificationCommand() {
260 String arg = getNextArg();
261 if (arg == null) {
262 onHelpNumberVerification();
263 return 0;
264 }
265
Hall Liuca5af3a2018-12-04 16:58:23 -0800266 if (!checkShellUid()) {
267 return -1;
268 }
269
Hall Liud892bec2018-11-30 14:51:45 -0800270 switch (arg) {
271 case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
Hall Liud892bec2018-11-30 14:51:45 -0800272 NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
273 return 0;
274 }
Hall Liuca5af3a2018-12-04 16:58:23 -0800275 case NUMBER_VERIFICATION_FAKE_CALL: {
276 boolean val = NumberVerificationManager.getInstance()
277 .checkIncomingCall(getNextArg());
278 getOutPrintWriter().println(val ? "1" : "0");
279 return 0;
280 }
Hall Liud892bec2018-11-30 14:51:45 -0800281 }
282
283 return -1;
284 }
285
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700286 // ims set-ims-service
287 private int handleImsSetServiceCommand() {
288 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700289 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700290 Boolean isCarrierService = null;
291
292 String opt;
293 while ((opt = getNextOption()) != null) {
294 switch (opt) {
295 case "-s": {
296 try {
297 slotId = Integer.parseInt(getNextArgRequired());
298 } catch (NumberFormatException e) {
299 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
300 return -1;
301 }
302 break;
303 }
304 case "-c": {
305 isCarrierService = true;
306 break;
307 }
308 case "-d": {
309 isCarrierService = false;
310 break;
311 }
312 }
313 }
314 // Mandatory param, either -c or -d
315 if (isCarrierService == null) {
316 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
317 return -1;
318 }
319
320 String packageName = getNextArg();
321
322 try {
323 if (packageName == null) {
324 packageName = "";
325 }
326 boolean result = mInterface.setImsService(slotId, isCarrierService, packageName);
327 if (VDBG) {
328 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
329 + (isCarrierService ? "-c " : "-d ") + packageName + ", result=" + result);
330 }
331 getOutPrintWriter().println(result);
332 } catch (RemoteException e) {
333 Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
334 + (isCarrierService ? "-c " : "-d ") + packageName + ", error"
335 + e.getMessage());
336 errPw.println("Exception: " + e.getMessage());
337 return -1;
338 }
339 return 0;
340 }
341
342 // ims get-ims-service
343 private int handleImsGetServiceCommand() {
344 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700345 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700346 Boolean isCarrierService = null;
347
348 String opt;
349 while ((opt = getNextOption()) != null) {
350 switch (opt) {
351 case "-s": {
352 try {
353 slotId = Integer.parseInt(getNextArgRequired());
354 } catch (NumberFormatException e) {
355 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
356 return -1;
357 }
358 break;
359 }
360 case "-c": {
361 isCarrierService = true;
362 break;
363 }
364 case "-d": {
365 isCarrierService = false;
366 break;
367 }
368 }
369 }
370 // Mandatory param, either -c or -d
371 if (isCarrierService == null) {
372 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
373 return -1;
374 }
375
376 String result;
377 try {
378 result = mInterface.getImsService(slotId, isCarrierService);
379 } catch (RemoteException e) {
380 return -1;
381 }
382 if (VDBG) {
383 Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
384 + (isCarrierService ? "-c " : "-d ") + ", returned: " + result);
385 }
386 getOutPrintWriter().println(result);
387 return 0;
388 }
389
390 private int handleEnableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700391 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700392 String opt;
393 while ((opt = getNextOption()) != null) {
394 switch (opt) {
395 case "-s": {
396 try {
397 slotId = Integer.parseInt(getNextArgRequired());
398 } catch (NumberFormatException e) {
399 getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID.");
400 return -1;
401 }
402 break;
403 }
404 }
405 }
406 try {
407 mInterface.enableIms(slotId);
408 } catch (RemoteException e) {
409 return -1;
410 }
411 if (VDBG) {
412 Log.v(LOG_TAG, "ims enable -s " + slotId);
413 }
414 return 0;
415 }
416
417 private int handleDisableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700418 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700419 String opt;
420 while ((opt = getNextOption()) != null) {
421 switch (opt) {
422 case "-s": {
423 try {
424 slotId = Integer.parseInt(getNextArgRequired());
425 } catch (NumberFormatException e) {
426 getErrPrintWriter().println(
427 "ims disable requires an integer as a SLOT_ID.");
428 return -1;
429 }
430 break;
431 }
432 }
433 }
434 try {
435 mInterface.disableIms(slotId);
436 } catch (RemoteException e) {
437 return -1;
438 }
439 if (VDBG) {
440 Log.v(LOG_TAG, "ims disable -s " + slotId);
441 }
442 return 0;
443 }
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700444
445 private int getDefaultSlot() {
446 int slotId = SubscriptionManager.getDefaultVoicePhoneId();
447 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
448 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
449 // If there is no default, default to slot 0.
450 slotId = DEFAULT_PHONE_ID;
451 }
452 return slotId;
453 }
sqian2fff4a32018-11-05 14:18:37 -0800454
Hall Liud892bec2018-11-30 14:51:45 -0800455 private boolean checkShellUid() {
Hall Liu2ddfc7e2018-12-06 13:09:45 -0800456 // adb can run as root or as shell, depending on whether the device is rooted.
457 return Binder.getCallingUid() == Process.SHELL_UID
458 || Binder.getCallingUid() == Process.ROOT_UID;
Hall Liud892bec2018-11-30 14:51:45 -0800459 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700460}