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