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 android.app.Activity; 20 import android.app.ActivityManager; 21 import android.app.ForegroundServiceStartNotAllowedException; 22 import android.app.IActivityManager; 23 import android.app.PendingIntent; 24 import android.content.BroadcastReceiver; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.ServiceConnection; 29 import android.content.pm.PackageManager; 30 import android.media.session.MediaSession; 31 import android.os.Bundle; 32 import android.os.IBinder; 33 import android.os.Parcel; 34 import android.os.RemoteCallback; 35 import android.os.RemoteException; 36 import android.text.TextUtils; 37 import android.util.ArrayMap; 38 import android.util.Log; 39 40 import java.util.concurrent.TimeUnit; 41 42 public class CommandReceiver extends BroadcastReceiver { 43 44 private static final String TAG = "CommandReceiver"; 45 46 // Requires flags and targetPackage 47 public static final int COMMAND_BIND_SERVICE = 1; 48 // Requires targetPackage 49 public static final int COMMAND_UNBIND_SERVICE = 2; 50 public static final int COMMAND_START_FOREGROUND_SERVICE = 3; 51 public static final int COMMAND_STOP_FOREGROUND_SERVICE = 4; 52 public static final int COMMAND_START_FOREGROUND_SERVICE_LOCATION = 5; 53 public static final int COMMAND_STOP_FOREGROUND_SERVICE_LOCATION = 6; 54 public static final int COMMAND_START_ALERT_SERVICE = 7; 55 public static final int COMMAND_STOP_ALERT_SERVICE = 8; 56 public static final int COMMAND_SELF_INDUCED_ANR = 9; 57 public static final int COMMAND_START_ACTIVITY = 10; 58 public static final int COMMAND_STOP_ACTIVITY = 11; 59 public static final int COMMAND_CREATE_FGSL_PENDING_INTENT = 12; 60 public static final int COMMAND_SEND_FGSL_PENDING_INTENT = 13; 61 public static final int COMMAND_BIND_FOREGROUND_SERVICE = 14; 62 public static final int COMMAND_START_CHILD_PROCESS = 15; 63 public static final int COMMAND_STOP_CHILD_PROCESS = 16; 64 public static final int COMMAND_WAIT_FOR_CHILD_PROCESS_GONE = 17; 65 public static final int COMMAND_START_SERVICE = 18; 66 public static final int COMMAND_STOP_SERVICE = 19; 67 public static final int COMMAND_START_FOREGROUND_SERVICE_STICKY = 20; 68 public static final int COMMAND_STOP_FOREGROUND_SERVICE_STICKY = 21; 69 public static final int COMMAND_EMPTY = 22; 70 public static final int COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME = 23; 71 public static final int COMMAND_CREATE_ACTIVE_MEDIA_SESSION = 24; 72 73 public static final int RESULT_CHILD_PROCESS_STARTED = IBinder.FIRST_CALL_TRANSACTION; 74 public static final int RESULT_CHILD_PROCESS_STOPPED = IBinder.FIRST_CALL_TRANSACTION + 1; 75 public static final int RESULT_CHILD_PROCESS_GONE = IBinder.FIRST_CALL_TRANSACTION + 2; 76 77 public static final String EXTRA_COMMAND = "android.app.stubs.extra.COMMAND"; 78 public static final String EXTRA_TARGET_PACKAGE = "android.app.stubs.extra.TARGET_PACKAGE"; 79 public static final String EXTRA_FLAGS = "android.app.stubs.extra.FLAGS"; 80 public static final String EXTRA_CALLBACK = "android.app.stubs.extra.callback"; 81 public static final String EXTRA_CHILD_CMDLINE = "android.app.stubs.extra.child_cmdline"; 82 public static final String EXTRA_TIMEOUT = "android.app.stubs.extra.child_cmdline"; 83 public static final String EXTRA_MESSENGER = "android.app.stubs.extra.EXTRA_MESSENGER"; 84 85 public static final String SERVICE_NAME = "android.app.stubs.LocalService"; 86 public static final String FG_SERVICE_NAME = "android.app.stubs.LocalForegroundService"; 87 public static final String FG_LOCATION_SERVICE_NAME = 88 "android.app.stubs.LocalForegroundServiceLocation"; 89 public static final String FG_STICKY_SERVICE_NAME = 90 "android.app.stubs.LocalForegroundServiceSticky"; 91 92 public static final String ACTIVITY_NAME = "android.app.stubs.SimpleActivity"; 93 94 private static ArrayMap<String,ServiceConnection> sServiceMap = new ArrayMap<>(); 95 96 // Map a packageName to a Intent that starts an Activity. 97 private static ArrayMap<String, Intent> sActivityIntent = new ArrayMap<>(); 98 99 // Map a packageName to a PendingIntent. 100 private static ArrayMap<String, PendingIntent> sPendingIntent = new ArrayMap<>(); 101 102 /** The child process, started via {@link #COMMAND_START_CHILD_PROCESS} */ 103 private static Process sChildProcess; 104 105 private static MediaSession mMediaSession = null; 106 107 /** 108 * Handle the different types of binding/unbinding requests. 109 * @param context The Context in which the receiver is running. 110 * @param intent The Intent being received. 111 */ 112 @Override onReceive(Context context, Intent intent)113 public void onReceive(Context context, Intent intent) { 114 // Use the application context as the receiver context could be restricted. 115 context = context.getApplicationContext(); 116 int command = intent.getIntExtra(EXTRA_COMMAND, -1); 117 Log.d(TAG + "_" + context.getPackageName(), "Got command " + command + ", intent=" 118 + intent); 119 switch (command) { 120 case COMMAND_BIND_SERVICE: 121 doBindService(context, intent, SERVICE_NAME); 122 break; 123 case COMMAND_UNBIND_SERVICE: 124 doUnbindService(context, intent); 125 break; 126 case COMMAND_START_FOREGROUND_SERVICE: 127 doStartForegroundService(context, intent); 128 break; 129 case COMMAND_START_SERVICE: 130 doStartService(context, intent); 131 break; 132 case COMMAND_STOP_FOREGROUND_SERVICE: 133 case COMMAND_STOP_SERVICE: 134 doStopService(context, intent, FG_SERVICE_NAME); 135 break; 136 case COMMAND_START_FOREGROUND_SERVICE_LOCATION: 137 doStartForegroundServiceWithType(context, intent); 138 break; 139 case COMMAND_STOP_FOREGROUND_SERVICE_LOCATION: 140 doStopService(context, intent, FG_LOCATION_SERVICE_NAME); 141 break; 142 case COMMAND_START_FOREGROUND_SERVICE_STICKY: 143 doStartForegroundServiceSticky(context, intent); 144 break; 145 case COMMAND_STOP_FOREGROUND_SERVICE_STICKY: 146 doStopService(context, intent, FG_STICKY_SERVICE_NAME); 147 break; 148 case COMMAND_START_ALERT_SERVICE: 149 doStartAlertService(context); 150 break; 151 case COMMAND_STOP_ALERT_SERVICE: 152 doStopAlertService(context); 153 break; 154 case COMMAND_SELF_INDUCED_ANR: 155 doSelfInducedAnr(context); 156 break; 157 case COMMAND_START_ACTIVITY: 158 doStartActivity(context, intent); 159 break; 160 case COMMAND_STOP_ACTIVITY: 161 doStopActivity(context, intent); 162 break; 163 case COMMAND_CREATE_FGSL_PENDING_INTENT: 164 doCreateFgslPendingIntent(context, intent); 165 break; 166 case COMMAND_SEND_FGSL_PENDING_INTENT: 167 doSendFgslPendingIntent(context, intent); 168 break; 169 case COMMAND_BIND_FOREGROUND_SERVICE: 170 doBindService(context, intent, FG_LOCATION_SERVICE_NAME); 171 break; 172 case COMMAND_START_CHILD_PROCESS: 173 doStartChildProcess(context, intent); 174 break; 175 case COMMAND_STOP_CHILD_PROCESS: 176 doStopChildProcess(context, intent); 177 break; 178 case COMMAND_WAIT_FOR_CHILD_PROCESS_GONE: 179 doWaitForChildProcessGone(context, intent); 180 break; 181 case COMMAND_EMPTY: 182 break; 183 case COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME: 184 doStartForegroundServiceSpoofPackageName(context, intent); 185 break; 186 case COMMAND_CREATE_ACTIVE_MEDIA_SESSION: 187 doStartMediaPlayback(context, intent.getParcelableExtra( 188 Intent.EXTRA_REMOTE_CALLBACK, RemoteCallback.class)); 189 break; 190 } 191 } 192 doBindService(Context context, Intent commandIntent, String serviceName)193 private void doBindService(Context context, Intent commandIntent, String serviceName) { 194 String targetPackage = getTargetPackage(commandIntent); 195 int flags = getFlags(commandIntent); 196 197 Intent bindIntent = new Intent(); 198 bindIntent.setComponent(new ComponentName(targetPackage, serviceName)); 199 200 ServiceConnection connection = addServiceConnection(targetPackage); 201 202 context.bindService(bindIntent, connection, flags | Context.BIND_AUTO_CREATE); 203 } 204 doUnbindService(Context context, Intent commandIntent)205 private void doUnbindService(Context context, Intent commandIntent) { 206 String targetPackage = getTargetPackage(commandIntent); 207 context.unbindService(sServiceMap.remove(targetPackage)); 208 } 209 doStartForegroundService(Context context, Intent commandIntent)210 private void doStartForegroundService(Context context, Intent commandIntent) { 211 String targetPackage = getTargetPackage(commandIntent); 212 Intent fgsIntent = new Intent(); 213 fgsIntent.putExtras(commandIntent); 214 fgsIntent.setComponent(new ComponentName(targetPackage, FG_SERVICE_NAME)); 215 int command = LocalForegroundService.COMMAND_START_FOREGROUND; 216 fgsIntent.putExtras(LocalForegroundService.newCommand(command)); 217 try { 218 context.startForegroundService(fgsIntent); 219 } catch (ForegroundServiceStartNotAllowedException e) { 220 Log.d(TAG, "startForegroundService gets an " 221 + " ForegroundServiceStartNotAllowedException", e); 222 } 223 } 224 doStartService(Context context, Intent commandIntent)225 private void doStartService(Context context, Intent commandIntent) { 226 String targetPackage = getTargetPackage(commandIntent); 227 Intent fgsIntent = new Intent(); 228 fgsIntent.putExtras(commandIntent); 229 fgsIntent.setComponent(new ComponentName(targetPackage, FG_SERVICE_NAME)); 230 context.startService(fgsIntent); 231 } 232 doStartForegroundServiceWithType(Context context, Intent commandIntent)233 private void doStartForegroundServiceWithType(Context context, Intent commandIntent) { 234 String targetPackage = getTargetPackage(commandIntent); 235 Intent fgsIntent = new Intent(); 236 fgsIntent.putExtras(commandIntent); // include the fg service type if any. 237 fgsIntent.setComponent(new ComponentName(targetPackage, FG_LOCATION_SERVICE_NAME)); 238 int command = LocalForegroundServiceLocation.COMMAND_START_FOREGROUND_WITH_TYPE; 239 fgsIntent.putExtras(LocalForegroundService.newCommand(command)); 240 try { 241 context.startForegroundService(fgsIntent); 242 } catch (ForegroundServiceStartNotAllowedException e) { 243 Log.d(TAG, "startForegroundService gets an " 244 + "ForegroundServiceStartNotAllowedException", e); 245 } 246 } 247 doStartForegroundServiceSticky(Context context, Intent commandIntent)248 private void doStartForegroundServiceSticky(Context context, Intent commandIntent) { 249 String targetPackage = getTargetPackage(commandIntent); 250 Intent fgsIntent = new Intent(); 251 fgsIntent.putExtras(commandIntent); 252 fgsIntent.setComponent(new ComponentName(targetPackage, FG_STICKY_SERVICE_NAME)); 253 int command = LocalForegroundService.COMMAND_START_FOREGROUND; 254 fgsIntent.putExtras(LocalForegroundService.newCommand(command)); 255 try { 256 context.startForegroundService(fgsIntent); 257 } catch (ForegroundServiceStartNotAllowedException e) { 258 Log.d(TAG, "startForegroundService gets an " 259 + "ForegroundServiceStartNotAllowedException", e); 260 } 261 } 262 doStopService(Context context, Intent commandIntent, String serviceName)263 private void doStopService(Context context, Intent commandIntent, 264 String serviceName) { 265 String targetPackage = getTargetPackage(commandIntent); 266 Intent fgsIntent = new Intent(); 267 fgsIntent.setComponent(new ComponentName(targetPackage, serviceName)); 268 context.stopService(fgsIntent); 269 } 270 doStartAlertService(Context context)271 private void doStartAlertService(Context context) { 272 Intent intent = new Intent(context, LocalAlertService.class); 273 intent.setAction(LocalAlertService.COMMAND_SHOW_ALERT); 274 context.startService(intent); 275 } 276 doStopAlertService(Context context)277 private void doStopAlertService(Context context) { 278 Intent intent = new Intent(context, LocalAlertService.class); 279 intent.setAction(LocalAlertService.COMMAND_HIDE_ALERT); 280 context.startService(intent); 281 } 282 doSelfInducedAnr(Context context)283 private void doSelfInducedAnr(Context context) { 284 ActivityManager am = context.getSystemService(ActivityManager.class); 285 am.appNotResponding("CTS - self induced"); 286 } 287 doStartActivity(Context context, Intent commandIntent)288 private void doStartActivity(Context context, Intent commandIntent) { 289 String targetPackage = getTargetPackage(commandIntent); 290 Intent activityIntent = new Intent(Intent.ACTION_MAIN); 291 sActivityIntent.put(targetPackage, activityIntent); 292 activityIntent.putExtras(commandIntent); 293 activityIntent.setComponent(new ComponentName(targetPackage, ACTIVITY_NAME)); 294 activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 295 context.startActivity(activityIntent); 296 } 297 doStopActivity(Context context, Intent commandIntent)298 private void doStopActivity(Context context, Intent commandIntent) { 299 String targetPackage = getTargetPackage(commandIntent); 300 Intent activityIntent = sActivityIntent.remove(targetPackage); 301 activityIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 302 activityIntent.putExtra("finish", true); 303 context.startActivity(activityIntent); 304 } 305 doCreateFgslPendingIntent(Context context, Intent commandIntent)306 private void doCreateFgslPendingIntent(Context context, Intent commandIntent) { 307 final String targetPackage = getTargetPackage(commandIntent); 308 final Intent intent = new Intent().setComponent( 309 new ComponentName(targetPackage, FG_LOCATION_SERVICE_NAME)); 310 int command = LocalForegroundServiceLocation.COMMAND_START_FOREGROUND_WITH_TYPE; 311 intent.putExtras(LocalForegroundService.newCommand(command)); 312 final PendingIntent pendingIntent = PendingIntent.getForegroundService(context, 0, 313 intent, PendingIntent.FLAG_IMMUTABLE); 314 sPendingIntent.put(targetPackage, pendingIntent); 315 } 316 doSendFgslPendingIntent(Context context, Intent commandIntent)317 private void doSendFgslPendingIntent(Context context, Intent commandIntent) { 318 final String targetPackage = getTargetPackage(commandIntent); 319 try { 320 ((PendingIntent) sPendingIntent.remove(targetPackage)).send(); 321 } catch (PendingIntent.CanceledException e) { 322 Log.e(TAG, "Caugtht exception:", e); 323 } 324 } 325 doStartChildProcess(Context context, Intent intent)326 private void doStartChildProcess(Context context, Intent intent) { 327 final Bundle extras = intent.getExtras(); 328 final IBinder callback = extras.getBinder(EXTRA_CALLBACK); 329 final String[] cmdline = extras.getStringArray(EXTRA_CHILD_CMDLINE); 330 final Parcel data = Parcel.obtain(); 331 final Parcel reply = Parcel.obtain(); 332 333 try { 334 sChildProcess = Runtime.getRuntime().exec(cmdline); 335 if (sChildProcess != null) { 336 Log.i(TAG, "Forked child: " + sChildProcess); 337 callback.transact(RESULT_CHILD_PROCESS_STARTED, data, reply, 0); 338 } // else the remote will fail with timeout 339 } catch (Exception e) { 340 Log.e(TAG, "Unable to execute command", e); 341 sChildProcess = null; 342 } finally { 343 data.recycle(); 344 reply.recycle(); 345 } 346 } 347 doStopChildProcess(Context context, Intent intent)348 private void doStopChildProcess(Context context, Intent intent) { 349 final Bundle extras = intent.getExtras(); 350 final IBinder callback = extras.getBinder(EXTRA_CALLBACK); 351 final long timeout = extras.getLong(EXTRA_TIMEOUT); 352 waitForChildProcessGone(true, callback, RESULT_CHILD_PROCESS_STOPPED, timeout); 353 } 354 doWaitForChildProcessGone(Context context, Intent intent)355 private void doWaitForChildProcessGone(Context context, Intent intent) { 356 final Bundle extras = intent.getExtras(); 357 final IBinder callback = extras.getBinder(EXTRA_CALLBACK); 358 final long timeout = extras.getLong(EXTRA_TIMEOUT); 359 waitForChildProcessGone(false, callback, RESULT_CHILD_PROCESS_GONE, timeout); 360 } 361 waitForChildProcessGone(final boolean destroy, final IBinder callback, final int transactionCode, final long timeout)362 private static synchronized void waitForChildProcessGone(final boolean destroy, 363 final IBinder callback, final int transactionCode, final long timeout) { 364 if (destroy) { 365 sChildProcess.destroy(); 366 } 367 new Thread(() -> { 368 final Parcel data = Parcel.obtain(); 369 final Parcel reply = Parcel.obtain(); 370 try { 371 if (sChildProcess != null && sChildProcess.isAlive()) { 372 final boolean exit = sChildProcess.waitFor(timeout, TimeUnit.MILLISECONDS); 373 if (exit) { 374 Log.i(TAG, "Child process died: " + sChildProcess); 375 callback.transact(transactionCode, data, reply, 0); 376 } else { 377 Log.w(TAG, "Child process is still alive: " + sChildProcess); 378 } 379 } else { 380 callback.transact(transactionCode, data, reply, 0); 381 } 382 } catch (Exception e) { 383 Log.e(TAG, "Error", e); 384 } finally { 385 data.recycle(); 386 reply.recycle(); 387 } 388 }).start(); 389 } 390 391 /** 392 * Directly call IActivityManager.startService() using a spoofed packageName which is known to 393 * be allowlisted by Android framework to be able to start foreground service 394 * from the background. Framework will disallow the foreground service to start from the 395 * background and a ForegroundServiceStartNotAllowedException will be caught. 396 * @param context 397 * @param commandIntent 398 */ doStartForegroundServiceSpoofPackageName(Context context, Intent commandIntent)399 private void doStartForegroundServiceSpoofPackageName(Context context, Intent commandIntent) { 400 String targetPackage = getTargetPackage(commandIntent); 401 Intent fgsIntent = new Intent(); 402 fgsIntent.putExtras(commandIntent); 403 fgsIntent.setComponent(new ComponentName(targetPackage, FG_SERVICE_NAME)); 404 int command = LocalForegroundService.COMMAND_START_FOREGROUND; 405 fgsIntent.putExtras(LocalForegroundService.newCommand(command)); 406 try { 407 final PackageManager pm = context.getPackageManager(); 408 String spoofPackageName = pm.getAttentionServicePackageName(); 409 if (TextUtils.isEmpty(spoofPackageName)) { 410 Log.d(TAG, "getAttentionServicePackageName() returns empty"); 411 spoofPackageName = pm.getSystemCaptionsServicePackageName(); 412 } 413 if (TextUtils.isEmpty(spoofPackageName)) { 414 Log.d(TAG, "getSystemCaptionsServicePackageName() returns empty"); 415 spoofPackageName = "android"; 416 } 417 Log.d(TAG, "spoofPackageName: " + spoofPackageName); 418 final IBinder activityProxy = android.os.ServiceManager.getService("activity"); 419 // Call IActivityManager.startService() directly using a spoofed packageName. 420 IActivityManager.Stub.asInterface(activityProxy).startService( 421 context.getIApplicationThread(), 422 fgsIntent, 423 null, 424 true, 425 spoofPackageName, 426 null, 427 android.os.Process.myUserHandle().getIdentifier() 428 ); 429 } catch (ForegroundServiceStartNotAllowedException e) { 430 Log.d(TAG, "startForegroundService gets an " 431 + " ForegroundServiceStartNotAllowedException", e); 432 } catch (LinkageError e) { 433 // IActivityManager.startService() is a hidden API, access hidden API could get 434 // LinkageError, consider the test as pass if we get LinkageError. 435 Log.d(TAG, "startForegroundService gets an LinkageError", e); 436 } catch (RemoteException e) { 437 Log.d(TAG, "startForegroundService gets an RemoteException", e); 438 } 439 } 440 doStartMediaPlayback(Context context, RemoteCallback callback)441 private void doStartMediaPlayback(Context context, RemoteCallback callback) { 442 mMediaSession = new MediaSession(context, TAG); 443 mMediaSession.setCallback(new MediaSession.Callback() { 444 @Override 445 public void onPlay() { 446 super.onPlay(); 447 final Intent fgsIntent = new Intent(context, LocalForegroundService.class); 448 fgsIntent.putExtras(LocalForegroundService.newCommand( 449 LocalForegroundService.COMMAND_START_FOREGROUND)); 450 try { 451 context.startForegroundService(fgsIntent); 452 } catch (ForegroundServiceStartNotAllowedException e) { 453 Log.e(TAG, "Error while trying to start an FGS", e); 454 } 455 } 456 457 @Override 458 public void onPause() { 459 super.onPause(); 460 final Intent intent = new Intent(context, LocalForegroundService.class); 461 intent.putExtras(LocalForegroundService.newCommand( 462 LocalForegroundService.COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION)); 463 context.startService(intent); 464 } 465 466 @Override 467 public void onStop() { 468 super.onStop(); 469 final Intent intent = new Intent(context, LocalForegroundService.class); 470 context.stopService(intent); 471 mMediaSession.release(); 472 } 473 }); 474 mMediaSession.setActive(true); 475 476 callback.sendResult(null); 477 } 478 getTargetPackage(Intent intent)479 private String getTargetPackage(Intent intent) { 480 return intent.getStringExtra(EXTRA_TARGET_PACKAGE); 481 } 482 getFlags(Intent intent)483 private int getFlags(Intent intent) { 484 return intent.getIntExtra(EXTRA_FLAGS, 0); 485 } 486 sendCommand(Context context, int command, String sourcePackage, String targetPackage, int flags, Bundle extras)487 public static void sendCommand(Context context, int command, String sourcePackage, 488 String targetPackage, int flags, Bundle extras) { 489 final Intent intent = makeIntent(command, sourcePackage, targetPackage, flags, extras); 490 Log.d(TAG, "Sending broadcast " + intent); 491 context.sendOrderedBroadcast(intent, null); 492 } 493 sendCommandWithResultReceiver(Context context, int command, String sourcePackage, String targetPackage, int flags, Bundle extras, BroadcastReceiver resultReceiver)494 public static void sendCommandWithResultReceiver(Context context, int command, 495 String sourcePackage, String targetPackage, int flags, Bundle extras, 496 BroadcastReceiver resultReceiver) { 497 final Intent intent = makeIntent(command, sourcePackage, targetPackage, flags, extras); 498 Log.d(TAG, "Sending broadcast with result receiver " + intent); 499 context.sendOrderedBroadcast(intent, null, resultReceiver, null, 500 Activity.RESULT_OK, null, null); 501 } 502 sendCommandWithBroadcastOptions(Context context, int command, String sourcePackage, String targetPackage, int flags, Bundle extras, Bundle broadcastOptions)503 public static void sendCommandWithBroadcastOptions(Context context, int command, 504 String sourcePackage, String targetPackage, int flags, Bundle extras, 505 Bundle broadcastOptions) { 506 final Intent intent = makeIntent(command, sourcePackage, targetPackage, flags, extras); 507 Log.d(TAG, "Sending broadcast with BroadcastOptions " + intent); 508 context.sendOrderedBroadcast(intent, null, broadcastOptions, null, null, 0, null, null); 509 } 510 makeIntent(int command, String sourcePackage, String targetPackage, int flags, Bundle extras)511 private static Intent makeIntent(int command, String sourcePackage, 512 String targetPackage, int flags, Bundle extras) { 513 Intent intent = new Intent(); 514 if (command == COMMAND_BIND_SERVICE || command == COMMAND_START_FOREGROUND_SERVICE 515 || command == COMMAND_STOP_FOREGROUND_SERVICE || command == COMMAND_START_ACTIVITY 516 || command == COMMAND_START_FOREGROUND_SERVICE_LOCATION || command == COMMAND_UNBIND_SERVICE) { 517 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); 518 } 519 intent.setComponent(new ComponentName(sourcePackage, "android.app.stubs.CommandReceiver")); 520 intent.putExtra(EXTRA_COMMAND, command); 521 intent.putExtra(EXTRA_FLAGS, flags); 522 intent.putExtra(EXTRA_TARGET_PACKAGE, targetPackage); 523 if (extras != null) { 524 intent.putExtras(extras); 525 } 526 return intent; 527 } 528 addServiceConnection(final String packageName)529 private ServiceConnection addServiceConnection(final String packageName) { 530 ServiceConnection connection = new ServiceConnection() { 531 @Override 532 public void onServiceConnected(ComponentName name, IBinder service) { 533 } 534 535 @Override 536 public void onServiceDisconnected(ComponentName name) { 537 } 538 }; 539 sServiceMap.put(packageName, connection); 540 return connection; 541 } 542 } 543