1 /* 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 17 package android.app.stubs; 18 19 import static android.content.ContentResolver.SCHEME_CONTENT; 20 21 import android.app.Activity; 22 import android.app.ActivityManager; 23 import android.app.BroadcastOptions; 24 import android.app.ForegroundServiceStartNotAllowedException; 25 import android.app.IActivityManager; 26 import android.app.Notification; 27 import android.app.NotificationChannel; 28 import android.app.NotificationManager; 29 import android.app.PendingIntent; 30 import android.content.BroadcastReceiver; 31 import android.content.ComponentName; 32 import android.content.Context; 33 import android.content.IContentProvider; 34 import android.content.Intent; 35 import android.content.IntentFilter; 36 import android.content.ServiceConnection; 37 import android.content.pm.PackageManager; 38 import android.media.session.MediaSession; 39 import android.media.session.PlaybackState; 40 import android.net.Uri; 41 import android.os.Bundle; 42 import android.os.IBinder; 43 import android.os.Parcel; 44 import android.os.RemoteCallback; 45 import android.os.RemoteException; 46 import android.text.TextUtils; 47 import android.util.ArrayMap; 48 import android.util.Log; 49 50 import java.util.concurrent.TimeUnit; 51 52 public class CommandReceiver extends BroadcastReceiver { 53 54 private static final String TAG = "CommandReceiver"; 55 56 // Requires flags and targetPackage 57 public static final int COMMAND_BIND_SERVICE = 1; 58 // Requires targetPackage 59 public static final int COMMAND_UNBIND_SERVICE = 2; 60 public static final int COMMAND_START_FOREGROUND_SERVICE = 3; 61 public static final int COMMAND_STOP_FOREGROUND_SERVICE = 4; 62 public static final int COMMAND_START_FOREGROUND_SERVICE_LOCATION = 5; 63 public static final int COMMAND_STOP_FOREGROUND_SERVICE_LOCATION = 6; 64 65 public static final int COMMAND_START_ALERT_SERVICE = 7; 66 public static final int COMMAND_STOP_ALERT_SERVICE = 8; 67 public static final int COMMAND_SELF_INDUCED_ANR = 9; 68 public static final int COMMAND_START_ACTIVITY = 10; 69 public static final int COMMAND_STOP_ACTIVITY = 11; 70 public static final int COMMAND_CREATE_FGSL_PENDING_INTENT = 12; 71 public static final int COMMAND_SEND_FGSL_PENDING_INTENT = 13; 72 public static final int COMMAND_BIND_FOREGROUND_SERVICE = 14; 73 public static final int COMMAND_START_CHILD_PROCESS = 15; 74 public static final int COMMAND_STOP_CHILD_PROCESS = 16; 75 public static final int COMMAND_WAIT_FOR_CHILD_PROCESS_GONE = 17; 76 public static final int COMMAND_START_SERVICE = 18; 77 public static final int COMMAND_STOP_SERVICE = 19; 78 public static final int COMMAND_START_FOREGROUND_SERVICE_STICKY = 20; 79 public static final int COMMAND_STOP_FOREGROUND_SERVICE_STICKY = 21; 80 public static final int COMMAND_EMPTY = 22; 81 public static final int COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME = 23; 82 public static final int COMMAND_CREATE_ACTIVE_MEDIA_SESSION = 24; 83 public static final int COMMAND_CREATE_MEDIA_SESSION_FGS_DELEGATE = 25; 84 public static final int COMMAND_ACTIVATE_MEDIA_SESSION_FGS_DELEGATE = 26; 85 public static final int COMMAND_DEACTIVATE_MEDIA_SESSION_FGS_DELEGATE = 27; 86 public static final int COMMAND_RELEASE_MEDIA_SESSION_FGS_DELEGATE = 28; 87 public static final int COMMAND_SEND_STICKY_BROADCAST = 29; 88 public static final int COMMAND_SET_MEDIA_SESSION_TO_PLAYING = 30; 89 public static final int COMMAND_SET_MEDIA_SESSION_TO_PAUSED = 31; 90 public static final int COMMAND_SET_MEDIA_SESSION_TO_STOPPED = 32; 91 public static final int COMMAND_CREATE_MEDIA_NOTIFICATION = 33; 92 public static final int COMMAND_ACQUIRE_CONTENT_PROVIDER = 34; 93 public static final int COMMAND_RELEASE_CONTENT_PROVIDER = 35; 94 public static final int COMMAND_START_FOREGROUND_SERVICE_MEDIA = 36; 95 public static final int COMMAND_STOP_FOREGROUND_SERVICE_MEDIA = 37; 96 public static final int COMMAND_START_SERVICE_MEDIA = 38; 97 98 public static final String KEY_PENDING_INTENT = "android.app.stubs.key.PENDING_INTENT"; 99 public static final String KEY_STICKY_BROADCAST_FILTER = 100 "android.app.stubs.key.STICKY_BROADCAST_FILTER"; 101 102 public static final int RESULT_CHILD_PROCESS_STARTED = IBinder.FIRST_CALL_TRANSACTION; 103 public static final int RESULT_CHILD_PROCESS_STOPPED = IBinder.FIRST_CALL_TRANSACTION + 1; 104 public static final int RESULT_CHILD_PROCESS_GONE = IBinder.FIRST_CALL_TRANSACTION + 2; 105 106 public static final String EXTRA_COMMAND = "android.app.stubs.extra.COMMAND"; 107 public static final String EXTRA_TARGET_PACKAGE = "android.app.stubs.extra.TARGET_PACKAGE"; 108 public static final String EXTRA_FLAGS = "android.app.stubs.extra.FLAGS"; 109 public static final String EXTRA_CALLBACK = "android.app.stubs.extra.callback"; 110 public static final String EXTRA_CHILD_CMDLINE = "android.app.stubs.extra.child_cmdline"; 111 public static final String EXTRA_TIMEOUT = "android.app.stubs.extra.child_cmdline"; 112 public static final String EXTRA_MESSENGER = "android.app.stubs.extra.EXTRA_MESSENGER"; 113 public static final String EXTRA_URI = "android.app.stubs.extra.EXTRA_URI"; 114 115 public static final String SERVICE_NAME = "android.app.stubs.LocalService"; 116 public static final String FG_SERVICE_NAME = "android.app.stubs.LocalForegroundService"; 117 public static final String FG_LOCATION_SERVICE_NAME = 118 "android.app.stubs.LocalForegroundServiceLocation"; 119 public static final String FG_STICKY_SERVICE_NAME = 120 "android.app.stubs.LocalForegroundServiceSticky"; 121 public static final String FG_MEDIA_SERVICE_NAME = 122 "android.app.stubs.LocalForegroundServiceMedia"; 123 124 public static final String ACTIVITY_NAME = "android.app.stubs.SimpleActivity"; 125 126 private static ArrayMap<String,ServiceConnection> sServiceMap = new ArrayMap<>(); 127 128 // Map a packageName to a Intent that starts an Activity. 129 private static ArrayMap<String, Intent> sActivityIntent = new ArrayMap<>(); 130 131 // Map a packageName to a PendingIntent. 132 private static ArrayMap<String, PendingIntent> sPendingIntent = new ArrayMap<>(); 133 134 /** The child process, started via {@link #COMMAND_START_CHILD_PROCESS} */ 135 private static Process sChildProcess; 136 137 private static MediaSession mMediaSession = null; 138 139 private String mNotificationChannelId; 140 private static final String NOTIFICATION_CHANNEL_ID = "com.example.android.media.channel"; 141 142 private int mNotificationId = 6003; 143 144 private static ArrayMap<Uri, IContentProvider> sContentProviders = new ArrayMap<>(); 145 146 /** 147 * Handle the different types of binding/unbinding requests. 148 * @param context The Context in which the receiver is running. 149 * @param intent The Intent being received. 150 */ 151 @Override onReceive(Context context, Intent intent)152 public void onReceive(Context context, Intent intent) { 153 // Use the application context as the receiver context could be restricted. 154 context = context.getApplicationContext(); 155 int command = intent.getIntExtra(EXTRA_COMMAND, -1); 156 Log.d(TAG + "_" + context.getPackageName(), "Got command " + command + ", intent=" 157 + intent); 158 Bundle resultExtras = null; 159 switch (command) { 160 case COMMAND_BIND_SERVICE: 161 doBindService(context, intent, SERVICE_NAME); 162 break; 163 case COMMAND_UNBIND_SERVICE: 164 doUnbindService(context, intent); 165 break; 166 case COMMAND_START_FOREGROUND_SERVICE: 167 doStartForegroundService(context, intent); 168 break; 169 case COMMAND_START_SERVICE: 170 doStartService(context, intent); 171 break; 172 case COMMAND_STOP_FOREGROUND_SERVICE: 173 case COMMAND_STOP_SERVICE: 174 doStopService(context, intent, FG_SERVICE_NAME); 175 break; 176 case COMMAND_START_FOREGROUND_SERVICE_LOCATION: 177 doStartForegroundServiceWithType(context, intent); 178 break; 179 case COMMAND_STOP_FOREGROUND_SERVICE_LOCATION: 180 doStopService(context, intent, FG_LOCATION_SERVICE_NAME); 181 break; 182 case COMMAND_START_FOREGROUND_SERVICE_STICKY: 183 doStartForegroundServiceSticky(context, intent); 184 break; 185 case COMMAND_STOP_FOREGROUND_SERVICE_STICKY: 186 doStopService(context, intent, FG_STICKY_SERVICE_NAME); 187 break; 188 case COMMAND_START_SERVICE_MEDIA: 189 doStartServiceMedia(context, intent); 190 break; 191 case COMMAND_START_FOREGROUND_SERVICE_MEDIA: 192 doStartForegroundServiceMedia(context, intent); 193 break; 194 case COMMAND_STOP_FOREGROUND_SERVICE_MEDIA: 195 doStopService(context, intent, FG_MEDIA_SERVICE_NAME); 196 break; 197 case COMMAND_START_ALERT_SERVICE: 198 doStartAlertService(context); 199 break; 200 case COMMAND_STOP_ALERT_SERVICE: 201 doStopAlertService(context); 202 break; 203 case COMMAND_SELF_INDUCED_ANR: 204 doSelfInducedAnr(context); 205 break; 206 case COMMAND_START_ACTIVITY: 207 doStartActivity(context, intent); 208 break; 209 case COMMAND_STOP_ACTIVITY: 210 doStopActivity(context, intent); 211 break; 212 case COMMAND_CREATE_FGSL_PENDING_INTENT: 213 final PendingIntent pendingIntent = doCreateFgslPendingIntent(context, intent); 214 resultExtras = new Bundle(); 215 resultExtras.putParcelable(KEY_PENDING_INTENT, pendingIntent); 216 break; 217 case COMMAND_SEND_FGSL_PENDING_INTENT: 218 doSendFgslPendingIntent(context, intent); 219 break; 220 case COMMAND_BIND_FOREGROUND_SERVICE: 221 doBindService(context, intent, FG_LOCATION_SERVICE_NAME); 222 break; 223 case COMMAND_START_CHILD_PROCESS: 224 doStartChildProcess(context, intent); 225 break; 226 case COMMAND_STOP_CHILD_PROCESS: 227 doStopChildProcess(context, intent); 228 break; 229 case COMMAND_WAIT_FOR_CHILD_PROCESS_GONE: 230 doWaitForChildProcessGone(context, intent); 231 break; 232 case COMMAND_EMPTY: 233 break; 234 case COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME: 235 doStartForegroundServiceSpoofPackageName(context, intent); 236 break; 237 case COMMAND_CREATE_ACTIVE_MEDIA_SESSION: 238 doStartMediaPlayback(context, intent.getParcelableExtra( 239 Intent.EXTRA_REMOTE_CALLBACK, RemoteCallback.class)); 240 break; 241 case COMMAND_CREATE_MEDIA_SESSION_FGS_DELEGATE: 242 doCreateMediaSession( 243 context, 244 intent.getParcelableExtra( 245 Intent.EXTRA_REMOTE_CALLBACK, RemoteCallback.class)); 246 break; 247 case COMMAND_ACTIVATE_MEDIA_SESSION_FGS_DELEGATE: 248 doChangeMediaSessionActiveState( 249 /* isActive= */ true, 250 intent.getParcelableExtra( 251 Intent.EXTRA_REMOTE_CALLBACK, RemoteCallback.class)); 252 break; 253 case COMMAND_DEACTIVATE_MEDIA_SESSION_FGS_DELEGATE: 254 doChangeMediaSessionActiveState( 255 /* isActive= */ false, 256 intent.getParcelableExtra( 257 Intent.EXTRA_REMOTE_CALLBACK, RemoteCallback.class)); 258 break; 259 case COMMAND_RELEASE_MEDIA_SESSION_FGS_DELEGATE: 260 doReleaseMediaSession( 261 intent.getParcelableExtra( 262 Intent.EXTRA_REMOTE_CALLBACK, RemoteCallback.class)); 263 break; 264 case COMMAND_SET_MEDIA_SESSION_TO_PLAYING: 265 doSetMediaSessionPlaybackState( 266 PlaybackState.STATE_PLAYING, 267 intent.getParcelableExtra( 268 Intent.EXTRA_REMOTE_CALLBACK, RemoteCallback.class)); 269 break; 270 case COMMAND_SET_MEDIA_SESSION_TO_PAUSED: 271 doSetMediaSessionPlaybackState( 272 PlaybackState.STATE_PAUSED, 273 intent.getParcelableExtra( 274 Intent.EXTRA_REMOTE_CALLBACK, RemoteCallback.class)); 275 break; 276 case COMMAND_SET_MEDIA_SESSION_TO_STOPPED: 277 doSetMediaSessionPlaybackState( 278 PlaybackState.STATE_STOPPED, 279 intent.getParcelableExtra( 280 Intent.EXTRA_REMOTE_CALLBACK, RemoteCallback.class)); 281 break; 282 case COMMAND_CREATE_MEDIA_NOTIFICATION: 283 doCreateMediaNotification( 284 context, 285 intent.getParcelableExtra( 286 Intent.EXTRA_REMOTE_CALLBACK, RemoteCallback.class)); 287 break; 288 case COMMAND_SEND_STICKY_BROADCAST: 289 final IntentFilter intentFilter = doSendStickyBroadcast(context); 290 resultExtras = new Bundle(); 291 if (intentFilter != null) { 292 resultExtras.putParcelable(KEY_STICKY_BROADCAST_FILTER, intentFilter); 293 } 294 break; 295 case COMMAND_ACQUIRE_CONTENT_PROVIDER: 296 doAcquireProvider(context, intent); 297 break; 298 case COMMAND_RELEASE_CONTENT_PROVIDER: 299 doReleaseProvider(context, intent); 300 break; 301 } 302 if (resultExtras != null) { 303 setResultExtras(resultExtras); 304 } 305 } 306 doBindService(Context context, Intent commandIntent, String serviceName)307 private void doBindService(Context context, Intent commandIntent, String serviceName) { 308 String targetPackage = getTargetPackage(commandIntent); 309 int flags = getFlags(commandIntent); 310 311 Intent bindIntent = new Intent(); 312 bindIntent.setComponent(new ComponentName(targetPackage, serviceName)); 313 314 ServiceConnection connection = addServiceConnection(targetPackage); 315 316 context.bindService(bindIntent, connection, flags | Context.BIND_AUTO_CREATE); 317 } 318 doUnbindService(Context context, Intent commandIntent)319 private void doUnbindService(Context context, Intent commandIntent) { 320 String targetPackage = getTargetPackage(commandIntent); 321 context.unbindService(sServiceMap.remove(targetPackage)); 322 } 323 doStartForegroundService(Context context, Intent commandIntent)324 private void doStartForegroundService(Context context, Intent commandIntent) { 325 String targetPackage = getTargetPackage(commandIntent); 326 Intent fgsIntent = new Intent(); 327 fgsIntent.putExtras(commandIntent); 328 fgsIntent.setComponent(new ComponentName(targetPackage, FG_SERVICE_NAME)); 329 int command = LocalForegroundService.COMMAND_START_FOREGROUND; 330 fgsIntent.putExtras(LocalForegroundService.newCommand(command)); 331 try { 332 context.startForegroundService(fgsIntent); 333 } catch (ForegroundServiceStartNotAllowedException e) { 334 Log.d(TAG, "startForegroundService gets an " 335 + " ForegroundServiceStartNotAllowedException", e); 336 } 337 } 338 doStartService(Context context, Intent commandIntent)339 private void doStartService(Context context, Intent commandIntent) { 340 String targetPackage = getTargetPackage(commandIntent); 341 Intent fgsIntent = new Intent(); 342 fgsIntent.putExtras(commandIntent); 343 fgsIntent.setComponent(new ComponentName(targetPackage, FG_SERVICE_NAME)); 344 context.startService(fgsIntent); 345 } 346 doStartForegroundServiceWithType(Context context, Intent commandIntent)347 private void doStartForegroundServiceWithType(Context context, Intent commandIntent) { 348 String targetPackage = getTargetPackage(commandIntent); 349 Intent fgsIntent = new Intent(); 350 fgsIntent.putExtras(commandIntent); // include the fg service type if any. 351 fgsIntent.setComponent(new ComponentName(targetPackage, FG_LOCATION_SERVICE_NAME)); 352 int command = LocalForegroundServiceLocation.COMMAND_START_FOREGROUND_WITH_TYPE; 353 fgsIntent.putExtras(LocalForegroundService.newCommand(command)); 354 try { 355 context.startForegroundService(fgsIntent); 356 } catch (ForegroundServiceStartNotAllowedException e) { 357 Log.d(TAG, "startForegroundService gets an " 358 + "ForegroundServiceStartNotAllowedException", e); 359 } 360 } 361 doStartServiceMedia(Context context, Intent commandIntent)362 private void doStartServiceMedia(Context context, Intent commandIntent) { 363 String targetPackage = getTargetPackage(commandIntent); 364 Intent fgsIntent = new Intent(); 365 fgsIntent.putExtras(commandIntent); 366 fgsIntent.setComponent(new ComponentName(targetPackage, FG_MEDIA_SERVICE_NAME)); 367 context.startService(fgsIntent); 368 } 369 doStartForegroundServiceMedia(Context context, Intent commandIntent)370 private void doStartForegroundServiceMedia(Context context, Intent commandIntent) { 371 String targetPackage = getTargetPackage(commandIntent); 372 Intent fgsIntent = new Intent(); 373 fgsIntent.putExtras(commandIntent); 374 fgsIntent.setComponent(new ComponentName(targetPackage, FG_MEDIA_SERVICE_NAME)); 375 int command = LocalForegroundServiceMedia.COMMAND_START_FOREGROUND_WITH_TYPE; 376 fgsIntent.putExtras(LocalForegroundService.newCommand(command)); 377 try { 378 context.startForegroundService(fgsIntent); 379 } catch (ForegroundServiceStartNotAllowedException e) { 380 Log.d(TAG, "startForegroundService gets an " 381 + "ForegroundServiceStartNotAllowedException", e); 382 } 383 } 384 doStartForegroundServiceSticky(Context context, Intent commandIntent)385 private void doStartForegroundServiceSticky(Context context, Intent commandIntent) { 386 String targetPackage = getTargetPackage(commandIntent); 387 Intent fgsIntent = new Intent(); 388 fgsIntent.putExtras(commandIntent); 389 fgsIntent.setComponent(new ComponentName(targetPackage, FG_STICKY_SERVICE_NAME)); 390 int command = LocalForegroundService.COMMAND_START_FOREGROUND; 391 fgsIntent.putExtras(LocalForegroundService.newCommand(command)); 392 try { 393 context.startForegroundService(fgsIntent); 394 } catch (ForegroundServiceStartNotAllowedException e) { 395 Log.d(TAG, "startForegroundService gets an " 396 + "ForegroundServiceStartNotAllowedException", e); 397 } 398 } 399 doStopService(Context context, Intent commandIntent, String serviceName)400 private void doStopService(Context context, Intent commandIntent, 401 String serviceName) { 402 String targetPackage = getTargetPackage(commandIntent); 403 Intent fgsIntent = new Intent(); 404 fgsIntent.setComponent(new ComponentName(targetPackage, serviceName)); 405 context.stopService(fgsIntent); 406 } 407 doStartAlertService(Context context)408 private void doStartAlertService(Context context) { 409 Intent intent = new Intent(context, LocalAlertService.class); 410 intent.setAction(LocalAlertService.COMMAND_SHOW_ALERT); 411 context.startService(intent); 412 } 413 doStopAlertService(Context context)414 private void doStopAlertService(Context context) { 415 Intent intent = new Intent(context, LocalAlertService.class); 416 intent.setAction(LocalAlertService.COMMAND_HIDE_ALERT); 417 context.startService(intent); 418 } 419 doSelfInducedAnr(Context context)420 private void doSelfInducedAnr(Context context) { 421 ActivityManager am = context.getSystemService(ActivityManager.class); 422 am.appNotResponding("CTS - self induced"); 423 } 424 doStartActivity(Context context, Intent commandIntent)425 private void doStartActivity(Context context, Intent commandIntent) { 426 String targetPackage = getTargetPackage(commandIntent); 427 Intent activityIntent = new Intent(Intent.ACTION_MAIN); 428 sActivityIntent.put(targetPackage, activityIntent); 429 activityIntent.putExtras(commandIntent); 430 activityIntent.setComponent(new ComponentName(targetPackage, ACTIVITY_NAME)); 431 activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 432 context.startActivity(activityIntent); 433 } 434 doStopActivity(Context context, Intent commandIntent)435 private void doStopActivity(Context context, Intent commandIntent) { 436 String targetPackage = getTargetPackage(commandIntent); 437 Intent activityIntent = sActivityIntent.remove(targetPackage); 438 activityIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 439 activityIntent.putExtra("finish", true); 440 context.startActivity(activityIntent); 441 } 442 doCreateFgslPendingIntent(Context context, Intent commandIntent)443 private PendingIntent doCreateFgslPendingIntent(Context context, Intent commandIntent) { 444 final String targetPackage = getTargetPackage(commandIntent); 445 final Intent intent = new Intent().setComponent( 446 new ComponentName(targetPackage, FG_LOCATION_SERVICE_NAME)); 447 int command = LocalForegroundServiceLocation.COMMAND_START_FOREGROUND_WITH_TYPE; 448 intent.putExtras(LocalForegroundService.newCommand(command)); 449 final PendingIntent pendingIntent = PendingIntent.getForegroundService(context, 0, 450 intent, PendingIntent.FLAG_IMMUTABLE); 451 sPendingIntent.put(targetPackage, pendingIntent); 452 return pendingIntent; 453 } 454 doSendFgslPendingIntent(Context context, Intent commandIntent)455 private void doSendFgslPendingIntent(Context context, Intent commandIntent) { 456 final String targetPackage = getTargetPackage(commandIntent); 457 try { 458 ((PendingIntent) sPendingIntent.remove(targetPackage)).send(); 459 } catch (PendingIntent.CanceledException e) { 460 Log.e(TAG, "Caugtht exception:", e); 461 } 462 } 463 doStartChildProcess(Context context, Intent intent)464 private void doStartChildProcess(Context context, Intent intent) { 465 final Bundle extras = intent.getExtras(); 466 final IBinder callback = extras.getBinder(EXTRA_CALLBACK); 467 final String[] cmdline = extras.getStringArray(EXTRA_CHILD_CMDLINE); 468 final Parcel data = Parcel.obtain(); 469 final Parcel reply = Parcel.obtain(); 470 471 try { 472 sChildProcess = Runtime.getRuntime().exec(cmdline); 473 if (sChildProcess != null) { 474 Log.i(TAG, "Forked child: " + sChildProcess); 475 callback.transact(RESULT_CHILD_PROCESS_STARTED, data, reply, 0); 476 } // else the remote will fail with timeout 477 } catch (Exception e) { 478 Log.e(TAG, "Unable to execute command", e); 479 sChildProcess = null; 480 } finally { 481 data.recycle(); 482 reply.recycle(); 483 } 484 } 485 doStopChildProcess(Context context, Intent intent)486 private void doStopChildProcess(Context context, Intent intent) { 487 final Bundle extras = intent.getExtras(); 488 final IBinder callback = extras.getBinder(EXTRA_CALLBACK); 489 final long timeout = extras.getLong(EXTRA_TIMEOUT); 490 waitForChildProcessGone(true, callback, RESULT_CHILD_PROCESS_STOPPED, timeout); 491 } 492 doWaitForChildProcessGone(Context context, Intent intent)493 private void doWaitForChildProcessGone(Context context, Intent intent) { 494 final Bundle extras = intent.getExtras(); 495 final IBinder callback = extras.getBinder(EXTRA_CALLBACK); 496 final long timeout = extras.getLong(EXTRA_TIMEOUT); 497 waitForChildProcessGone(false, callback, RESULT_CHILD_PROCESS_GONE, timeout); 498 } 499 waitForChildProcessGone(final boolean destroy, final IBinder callback, final int transactionCode, final long timeout)500 private static synchronized void waitForChildProcessGone(final boolean destroy, 501 final IBinder callback, final int transactionCode, final long timeout) { 502 if (destroy) { 503 sChildProcess.destroy(); 504 } 505 new Thread(() -> { 506 final Parcel data = Parcel.obtain(); 507 final Parcel reply = Parcel.obtain(); 508 try { 509 if (sChildProcess != null && sChildProcess.isAlive()) { 510 final boolean exit = sChildProcess.waitFor(timeout, TimeUnit.MILLISECONDS); 511 if (exit) { 512 Log.i(TAG, "Child process died: " + sChildProcess); 513 callback.transact(transactionCode, data, reply, 0); 514 } else { 515 Log.w(TAG, "Child process is still alive: " + sChildProcess); 516 } 517 } else { 518 callback.transact(transactionCode, data, reply, 0); 519 } 520 } catch (Exception e) { 521 Log.e(TAG, "Error", e); 522 } finally { 523 data.recycle(); 524 reply.recycle(); 525 } 526 }).start(); 527 } 528 529 /** 530 * Directly call IActivityManager.startService() using a spoofed packageName which is known to 531 * be allowlisted by Android framework to be able to start foreground service 532 * from the background. Framework will disallow the foreground service to start from the 533 * background and a ForegroundServiceStartNotAllowedException will be caught. 534 * @param context 535 * @param commandIntent 536 */ doStartForegroundServiceSpoofPackageName(Context context, Intent commandIntent)537 private void doStartForegroundServiceSpoofPackageName(Context context, Intent commandIntent) { 538 String targetPackage = getTargetPackage(commandIntent); 539 Intent fgsIntent = new Intent(); 540 fgsIntent.putExtras(commandIntent); 541 fgsIntent.setComponent(new ComponentName(targetPackage, FG_SERVICE_NAME)); 542 int command = LocalForegroundService.COMMAND_START_FOREGROUND; 543 fgsIntent.putExtras(LocalForegroundService.newCommand(command)); 544 try { 545 final PackageManager pm = context.getPackageManager(); 546 String spoofPackageName = pm.getAttentionServicePackageName(); 547 if (TextUtils.isEmpty(spoofPackageName)) { 548 Log.d(TAG, "getAttentionServicePackageName() returns empty"); 549 spoofPackageName = pm.getSystemCaptionsServicePackageName(); 550 } 551 if (TextUtils.isEmpty(spoofPackageName)) { 552 Log.d(TAG, "getSystemCaptionsServicePackageName() returns empty"); 553 spoofPackageName = "android"; 554 } 555 Log.d(TAG, "spoofPackageName: " + spoofPackageName); 556 final IBinder activityProxy = android.os.ServiceManager.getService("activity"); 557 // Call IActivityManager.startService() directly using a spoofed packageName. 558 IActivityManager.Stub.asInterface(activityProxy).startService( 559 context.getIApplicationThread(), 560 fgsIntent, 561 null, 562 true, 563 spoofPackageName, 564 null, 565 android.os.Process.myUserHandle().getIdentifier() 566 ); 567 } catch (ForegroundServiceStartNotAllowedException e) { 568 Log.d(TAG, "startForegroundService gets an " 569 + " ForegroundServiceStartNotAllowedException", e); 570 } catch (LinkageError e) { 571 // IActivityManager.startService() is a hidden API, access hidden API could get 572 // LinkageError, consider the test as pass if we get LinkageError. 573 Log.d(TAG, "startForegroundService gets an LinkageError", e); 574 } catch (RemoteException e) { 575 Log.d(TAG, "startForegroundService gets an RemoteException", e); 576 } 577 } 578 doStartMediaPlayback(Context context, RemoteCallback callback)579 private void doStartMediaPlayback(Context context, RemoteCallback callback) { 580 mMediaSession = new MediaSession(context, TAG); 581 mMediaSession.setCallback(new MediaSession.Callback() { 582 @Override 583 public void onPlay() { 584 super.onPlay(); 585 final Intent fgsIntent = new Intent(context, LocalForegroundService.class); 586 fgsIntent.putExtras(LocalForegroundService.newCommand( 587 LocalForegroundService.COMMAND_START_FOREGROUND)); 588 try { 589 context.startForegroundService(fgsIntent); 590 } catch (ForegroundServiceStartNotAllowedException e) { 591 Log.e(TAG, "Error while trying to start an FGS", e); 592 } 593 } 594 595 @Override 596 public void onPause() { 597 super.onPause(); 598 final Intent intent = new Intent(context, LocalForegroundService.class); 599 intent.putExtras(LocalForegroundService.newCommand( 600 LocalForegroundService.COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION)); 601 context.startService(intent); 602 } 603 604 @Override 605 public void onStop() { 606 super.onStop(); 607 final Intent intent = new Intent(context, LocalForegroundService.class); 608 context.stopService(intent); 609 mMediaSession.release(); 610 } 611 }); 612 mMediaSession.setActive(true); 613 614 callback.sendResult(null); 615 } 616 617 /** Use FGS delegate to promote the app's procstate and provide keep-alive. */ doCreateMediaSession(Context context, RemoteCallback callback)618 private void doCreateMediaSession(Context context, RemoteCallback callback) { 619 mMediaSession = new MediaSession(context, TAG); 620 mMediaSession.setCallback( 621 new MediaSession.Callback() { 622 @Override 623 public void onPlay() { 624 super.onPlay(); 625 setPlaybackState(PlaybackState.STATE_PLAYING, mMediaSession); 626 } 627 628 @Override 629 public void onPause() { 630 super.onPause(); 631 setPlaybackState(PlaybackState.STATE_PAUSED, mMediaSession); 632 } 633 634 @Override 635 public void onStop() { 636 super.onStop(); 637 setPlaybackState(PlaybackState.STATE_STOPPED, mMediaSession); 638 } 639 }); 640 callback.sendResult(null); 641 } 642 doChangeMediaSessionActiveState(boolean isActive, RemoteCallback callback)643 private void doChangeMediaSessionActiveState(boolean isActive, RemoteCallback callback) { 644 if (mMediaSession != null) { 645 mMediaSession.setActive(isActive); 646 } 647 callback.sendResult(null); 648 } 649 doReleaseMediaSession(RemoteCallback callback)650 private void doReleaseMediaSession(RemoteCallback callback) { 651 if (mMediaSession != null) { 652 mMediaSession.release(); 653 } 654 callback.sendResult(null); 655 } 656 doSendStickyBroadcast(Context context)657 private IntentFilter doSendStickyBroadcast(Context context) { 658 final String action = "android.app.stubs.action.TEST"; 659 final Intent stickyIntent = new Intent(action); 660 final Uri uri = new Uri.Builder() 661 .scheme(SCHEME_CONTENT) 662 .authority(TestProvider.AUTHORITY) 663 .build(); 664 stickyIntent.setData(uri); 665 context.sendStickyBroadcast(stickyIntent); 666 final IntentFilter intentFilter = new IntentFilter(action); 667 try { 668 intentFilter.addDataType(TestProvider.TYPE); 669 } catch (IntentFilter.MalformedMimeTypeException e) { 670 Log.e(TAG, "Error setting the data type: " + TestProvider.TYPE); 671 return null; 672 } 673 return intentFilter; 674 675 } 676 doCreateMediaNotification(Context context, RemoteCallback callback)677 private void doCreateMediaNotification(Context context, RemoteCallback callback) { 678 NotificationManager notificationManager = 679 context.getSystemService(NotificationManager.class); 680 maybeCreateNotificationChannel(notificationManager); 681 Notification notification = 682 new Notification.Builder(context, mNotificationChannelId) 683 .setContentTitle("Track title") 684 .setSmallIcon(R.drawable.ic_call_answer) 685 .setContentText("Artist - Album") 686 .setStyle( 687 new Notification.MediaStyle() 688 .setMediaSession(mMediaSession.getSessionToken())) 689 .setAutoCancel(false) 690 .build(); 691 692 notificationManager.notify(mNotificationId++, notification); 693 callback.sendResult(null); 694 } 695 maybeCreateNotificationChannel(NotificationManager notificationManager)696 private void maybeCreateNotificationChannel(NotificationManager notificationManager) { 697 if (mNotificationChannelId != null) { 698 return; 699 } 700 mNotificationChannelId = NOTIFICATION_CHANNEL_ID; 701 // Create the NotificationChannel, but only on API 26+ because 702 // the NotificationChannel class is new and not in the support library 703 CharSequence name = "Channel"; 704 String description = "Description"; 705 int importance = NotificationManager.IMPORTANCE_LOW; 706 NotificationChannel channel = 707 new NotificationChannel(mNotificationChannelId, name.toString(), importance); 708 channel.setDescription(description); 709 710 // Register the channel with the system; you can't change the importance 711 // or other notification behaviors after this 712 notificationManager.createNotificationChannel(channel); 713 } 714 doAcquireProvider(Context context, Intent intent)715 private void doAcquireProvider(Context context, Intent intent) { 716 final Bundle extras = intent.getExtras(); 717 final Uri uri = extras.getParcelable(EXTRA_URI, Uri.class); 718 final IContentProvider provider = context.getContentResolver().acquireProvider(uri); 719 sContentProviders.put(uri, provider); 720 } 721 doReleaseProvider(Context context, Intent intent)722 private void doReleaseProvider(Context context, Intent intent) { 723 final Bundle extras = intent.getExtras(); 724 final Uri uri = extras.getParcelable(EXTRA_URI, Uri.class); 725 final IContentProvider provider = sContentProviders.remove(uri); 726 if (provider == null) return; 727 context.getContentResolver().releaseProvider(provider); 728 } 729 setPlaybackState(int state, MediaSession mediaSession)730 private void setPlaybackState(int state, MediaSession mediaSession) { 731 final long allActions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE 732 | PlaybackState.ACTION_PLAY_PAUSE | PlaybackState.ACTION_STOP 733 | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS 734 | PlaybackState.ACTION_FAST_FORWARD | PlaybackState.ACTION_REWIND; 735 PlaybackState playbackState = new PlaybackState.Builder().setActions(allActions) 736 .setState(state, 0L, 0.0f).build(); 737 mediaSession.setPlaybackState(playbackState); 738 } 739 doSetMediaSessionPlaybackState( @laybackState.State int state, RemoteCallback callback)740 private void doSetMediaSessionPlaybackState( 741 @PlaybackState.State int state, RemoteCallback callback) { 742 if (mMediaSession != null) { 743 setPlaybackState(state, mMediaSession); 744 } 745 callback.sendResult(null); 746 } 747 getTargetPackage(Intent intent)748 private String getTargetPackage(Intent intent) { 749 return intent.getStringExtra(EXTRA_TARGET_PACKAGE); 750 } 751 getFlags(Intent intent)752 private int getFlags(Intent intent) { 753 return intent.getIntExtra(EXTRA_FLAGS, 0); 754 } 755 sendCommand(Context context, int command, String sourcePackage, String targetPackage, int flags, Bundle extras)756 public static void sendCommand(Context context, int command, String sourcePackage, 757 String targetPackage, int flags, Bundle extras) { 758 final Intent intent = makeIntent(command, sourcePackage, targetPackage, flags, extras); 759 Log.d(TAG, "Sending broadcast " + intent); 760 sendOrderedBroadcast(context, intent, null /* resultReceiver */, 761 null /* broadcastOptions */); 762 } 763 sendCommandWithResultReceiver(Context context, int command, String sourcePackage, String targetPackage, int flags, Bundle extras, BroadcastReceiver resultReceiver)764 public static void sendCommandWithResultReceiver(Context context, int command, 765 String sourcePackage, String targetPackage, int flags, Bundle extras, 766 BroadcastReceiver resultReceiver) { 767 final Intent intent = makeIntent(command, sourcePackage, targetPackage, flags, extras); 768 Log.d(TAG, "Sending broadcast with result receiver " + intent); 769 sendOrderedBroadcast(context, intent, resultReceiver, null /* broadcastOptions */); 770 } 771 sendCommandWithBroadcastOptions(Context context, int command, String sourcePackage, String targetPackage, int flags, Bundle extras, BroadcastOptions broadcastOptions)772 public static void sendCommandWithBroadcastOptions(Context context, int command, 773 String sourcePackage, String targetPackage, int flags, Bundle extras, 774 BroadcastOptions broadcastOptions) { 775 final Intent intent = makeIntent(command, sourcePackage, targetPackage, flags, extras); 776 Log.d(TAG, "Sending broadcast with BroadcastOptions " + intent); 777 sendOrderedBroadcast(context, intent, null /* resultReceiver */, broadcastOptions); 778 } 779 sendOrderedBroadcast(Context context, Intent intent, BroadcastReceiver resultReceiver, BroadcastOptions broadcastOptions)780 private static void sendOrderedBroadcast(Context context, Intent intent, 781 BroadcastReceiver resultReceiver, BroadcastOptions broadcastOptions) { 782 final BroadcastOptions effectiveOptions = broadcastOptions == null 783 ? BroadcastOptions.makeBasic() : broadcastOptions; 784 effectiveOptions.setDebugLogEnabled(true); 785 context.sendOrderedBroadcast(intent, null /* receiverPermission */, 786 effectiveOptions.toBundle(), resultReceiver, null /* scheduler */, 787 Activity.RESULT_OK, null /* initialData */, null /* initialExtras */); 788 } 789 makeIntent(int command, String sourcePackage, String targetPackage, int flags, Bundle extras)790 private static Intent makeIntent(int command, String sourcePackage, 791 String targetPackage, int flags, Bundle extras) { 792 Intent intent = new Intent(); 793 if (command == COMMAND_BIND_SERVICE || command == COMMAND_START_FOREGROUND_SERVICE 794 || command == COMMAND_STOP_FOREGROUND_SERVICE || command == COMMAND_START_ACTIVITY 795 || command == COMMAND_START_FOREGROUND_SERVICE_LOCATION || command == COMMAND_UNBIND_SERVICE) { 796 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); 797 } 798 intent.setComponent(new ComponentName(sourcePackage, "android.app.stubs.CommandReceiver")); 799 intent.putExtra(EXTRA_COMMAND, command); 800 intent.putExtra(EXTRA_FLAGS, flags); 801 intent.putExtra(EXTRA_TARGET_PACKAGE, targetPackage); 802 if (extras != null) { 803 intent.putExtras(extras); 804 } 805 return intent; 806 } 807 addServiceConnection(final String packageName)808 private ServiceConnection addServiceConnection(final String packageName) { 809 ServiceConnection connection = new ServiceConnection() { 810 @Override 811 public void onServiceConnected(ComponentName name, IBinder service) { 812 } 813 814 @Override 815 public void onServiceDisconnected(ComponentName name) { 816 } 817 }; 818 sServiceMap.put(packageName, connection); 819 return connection; 820 } 821 } 822