1 /* 2 * Copyright (C) 2010 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 com.android.internal.content; 18 19 import android.annotation.NonNull; 20 import android.app.Activity; 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.pm.Flags; 26 import android.content.pm.PackageManager; 27 import android.net.Uri; 28 import android.os.Bundle; 29 import android.os.Handler; 30 import android.os.HandlerExecutor; 31 import android.os.IRemoteCallback; 32 import android.os.Looper; 33 import android.os.RemoteException; 34 import android.os.UserHandle; 35 import android.util.Log; 36 import android.util.Slog; 37 38 import com.android.internal.annotations.VisibleForTesting; 39 import com.android.internal.annotations.WeaklyReferencedCallback; 40 import com.android.internal.os.BackgroundThread; 41 42 import java.lang.ref.WeakReference; 43 import java.util.Objects; 44 import java.util.concurrent.Executor; 45 46 /** 47 * Helper class for monitoring the state of packages: adding, removing, 48 * updating, and disappearing and reappearing on the SD card. 49 */ 50 @WeaklyReferencedCallback 51 public abstract class PackageMonitor extends android.content.BroadcastReceiver { 52 static final String TAG = "PackageMonitor"; 53 54 Context mRegisteredContext; 55 Handler mRegisteredHandler; 56 String[] mDisappearingPackages; 57 String[] mAppearingPackages; 58 String[] mModifiedPackages; 59 int mChangeType; 60 int mChangeUserId = UserHandle.USER_NULL; 61 boolean mSomePackagesChanged; 62 String[] mModifiedComponents; 63 64 String[] mTempArray = new String[1]; 65 66 PackageMonitorCallback mPackageMonitorCallback; 67 68 private Executor mExecutor; 69 70 final boolean mSupportsPackageRestartQuery; 71 72 @UnsupportedAppUsage PackageMonitor()73 public PackageMonitor() { 74 // If the feature flag is enabled, set mSupportsPackageRestartQuery to false by default 75 this(!Flags.packageRestartQueryDisabledByDefault()); 76 } 77 78 /** 79 * The constructor of PackageMonitor whose parameters clearly indicate whether support 80 * querying package restart event. 81 */ PackageMonitor(boolean supportsPackageRestartQuery)82 public PackageMonitor(boolean supportsPackageRestartQuery) { 83 mSupportsPackageRestartQuery = supportsPackageRestartQuery; 84 } 85 getPackageFilter()86 private IntentFilter getPackageFilter() { 87 final boolean isCore = UserHandle.isCore(android.os.Process.myUid()); 88 89 IntentFilter filter = new IntentFilter(); 90 // Settings app sends the broadcast 91 filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 92 filter.addDataScheme("package"); 93 if (isCore) { 94 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 95 } 96 return filter; 97 } 98 99 @UnsupportedAppUsage register(Context context, Looper thread, boolean externalStorage)100 public void register(Context context, Looper thread, boolean externalStorage) { 101 register(context, thread, null, externalStorage); 102 } 103 104 @UnsupportedAppUsage register(Context context, Looper thread, UserHandle user, boolean externalStorage)105 public void register(Context context, Looper thread, UserHandle user, 106 boolean externalStorage) { 107 register(context, user, 108 (thread == null) ? BackgroundThread.getHandler() : new Handler(thread)); 109 } 110 111 /** 112 * Register for notifications of package changes such as install, removal and other events. 113 */ register(Context context, UserHandle user, Handler handler)114 public void register(Context context, UserHandle user, Handler handler) { 115 if (mRegisteredContext != null) { 116 throw new IllegalStateException("Already registered"); 117 } 118 mRegisteredContext = context; 119 mRegisteredHandler = Objects.requireNonNull(handler); 120 if (mSupportsPackageRestartQuery) { 121 final IntentFilter filter = getPackageFilter(); 122 if (user != null) { 123 context.registerReceiverAsUser(this, user, filter, null, mRegisteredHandler); 124 } else { 125 context.registerReceiver(this, filter, null, mRegisteredHandler); 126 } 127 } 128 if (mPackageMonitorCallback == null) { 129 PackageManager pm = mRegisteredContext.getPackageManager(); 130 if (pm != null) { 131 mExecutor = new HandlerExecutor(mRegisteredHandler); 132 mPackageMonitorCallback = new PackageMonitorCallback(this); 133 int userId = user != null ? user.getIdentifier() : mRegisteredContext.getUserId(); 134 pm.registerPackageMonitorCallback(mPackageMonitorCallback, userId); 135 } 136 } 137 } 138 getRegisteredHandler()139 public Handler getRegisteredHandler() { 140 return mRegisteredHandler; 141 } 142 143 @UnsupportedAppUsage unregister()144 public void unregister() { 145 if (mRegisteredContext == null) { 146 throw new IllegalStateException("Not registered"); 147 } 148 if (mSupportsPackageRestartQuery) { 149 mRegisteredContext.unregisterReceiver(this); 150 } 151 152 PackageManager pm = mRegisteredContext.getPackageManager(); 153 if (pm != null && mPackageMonitorCallback != null) { 154 pm.unregisterPackageMonitorCallback(mPackageMonitorCallback); 155 } 156 mPackageMonitorCallback = null; 157 mRegisteredContext = null; 158 mExecutor = null; 159 } 160 onBeginPackageChanges()161 public void onBeginPackageChanges() { 162 } 163 164 /** 165 * Called when a package is really added (and not replaced). 166 */ onPackageAdded(String packageName, int uid)167 public void onPackageAdded(String packageName, int uid) { 168 } 169 170 /** 171 * Same as {@link #onPackageAdded(String, int)}, but this callback 172 * has extras passed in. 173 */ onPackageAddedWithExtras(String packageName, int uid, Bundle extras)174 public void onPackageAddedWithExtras(String packageName, int uid, Bundle extras) { 175 } 176 177 /** 178 * Called when a package is really removed (and not replaced). 179 */ 180 @UnsupportedAppUsage onPackageRemoved(String packageName, int uid)181 public void onPackageRemoved(String packageName, int uid) { 182 } 183 184 /** 185 * Same as {@link #onPackageRemoved(String, int)}, but this callback 186 * has extras passed in. 187 */ onPackageRemovedWithExtras(String packageName, int uid, Bundle extras)188 public void onPackageRemovedWithExtras(String packageName, int uid, Bundle extras) { 189 } 190 191 /** 192 * Called when a package is really removed (and not replaced) for 193 * all users on the device. 194 */ onPackageRemovedAllUsers(String packageName, int uid)195 public void onPackageRemovedAllUsers(String packageName, int uid) { 196 } 197 198 /** 199 * Same as {@link #onPackageRemovedAllUsers(String, int)}, but this callback 200 * has extras passed in. 201 */ onPackageRemovedAllUsersWithExtras(String packageName, int uid, Bundle extras)202 public void onPackageRemovedAllUsersWithExtras(String packageName, int uid, Bundle extras) { 203 } 204 onPackageUpdateStarted(String packageName, int uid)205 public void onPackageUpdateStarted(String packageName, int uid) { 206 } 207 208 /** 209 * Same as {@link #onPackageUpdateStarted(String, int)}, but this callback 210 * has extras passed in. 211 */ onPackageUpdateStartedWithExtras(String packageName, int uid, Bundle extras)212 public void onPackageUpdateStartedWithExtras(String packageName, int uid, Bundle extras) { 213 } 214 onPackageUpdateFinished(String packageName, int uid)215 public void onPackageUpdateFinished(String packageName, int uid) { 216 } 217 218 /** 219 * Same as {@link #onPackageUpdateFinished(String, int)}, but this callback 220 * has extras passed in. 221 */ onPackageUpdateFinishedWithExtras(String packageName, int uid, Bundle extras)222 public void onPackageUpdateFinishedWithExtras(String packageName, int uid, Bundle extras) { 223 } 224 225 /** 226 * Direct reflection of {@link Intent#ACTION_PACKAGE_CHANGED 227 * Intent.ACTION_PACKAGE_CHANGED} being received, informing you of 228 * changes to the enabled/disabled state of components in a package 229 * and/or of the overall package. 230 * 231 * @param packageName The name of the package that is changing. 232 * @param uid The user ID the package runs under. 233 * @param components Any components in the package that are changing. If 234 * the overall package is changing, this will contain an entry of the 235 * package name itself. 236 * @return Return true to indicate you care about this change, which will 237 * result in {@link #onSomePackagesChanged()} being called later. If you 238 * return false, no further callbacks will happen about this change. The 239 * default implementation returns true if this is a change to the entire 240 * package. 241 */ 242 @UnsupportedAppUsage onPackageChanged(String packageName, int uid, String[] components)243 public boolean onPackageChanged(String packageName, int uid, String[] components) { 244 if (components != null) { 245 for (String name : components) { 246 if (packageName.equals(name)) { 247 return true; 248 } 249 } 250 } 251 return false; 252 } 253 254 /** 255 * Direct reflection of {@link Intent#ACTION_PACKAGE_CHANGED 256 * Intent.ACTION_PACKAGE_CHANGED} being received, this callback 257 * has extras passed in. 258 */ onPackageChangedWithExtras(String packageName, Bundle extras)259 public void onPackageChangedWithExtras(String packageName, Bundle extras) { 260 } 261 onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit, Bundle extras)262 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit, 263 Bundle extras) { 264 return onHandleForceStop(intent, packages, uid, doit); 265 } 266 onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit)267 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 268 return false; 269 } 270 onUidRemoved(int uid)271 public void onUidRemoved(int uid) { 272 } 273 onPackagesAvailable(String[] packages)274 public void onPackagesAvailable(String[] packages) { 275 } 276 onPackagesUnavailable(String[] packages)277 public void onPackagesUnavailable(String[] packages) { 278 } 279 onPackagesSuspended(String[] packages)280 public void onPackagesSuspended(String[] packages) { 281 } 282 onPackagesUnsuspended(String[] packages)283 public void onPackagesUnsuspended(String[] packages) { 284 } 285 286 public static final int PACKAGE_UNCHANGED = 0; 287 public static final int PACKAGE_UPDATING = 1; 288 public static final int PACKAGE_TEMPORARY_CHANGE = 2; 289 public static final int PACKAGE_PERMANENT_CHANGE = 3; 290 291 /** 292 * Called when a package disappears for any reason. 293 */ onPackageDisappeared(String packageName, int reason)294 public void onPackageDisappeared(String packageName, int reason) { 295 } 296 297 /** 298 * Called when a package disappears with extras passed in. 299 */ onPackageDisappearedWithExtras(String packageName, Bundle extras)300 public void onPackageDisappearedWithExtras(String packageName, Bundle extras) { 301 } 302 303 /** 304 * Called when a package appears for any reason. 305 */ onPackageAppeared(String packageName, int reason)306 public void onPackageAppeared(String packageName, int reason) { 307 } 308 309 310 /** 311 * Called when a package appears with extras passed in. 312 */ onPackageAppearedWithExtras(String packageName, Bundle extras)313 public void onPackageAppearedWithExtras(String packageName, Bundle extras) { 314 } 315 316 /** 317 * Called when an existing package is updated or its disabled state changes. 318 */ onPackageModified(@onNull String packageName)319 public void onPackageModified(@NonNull String packageName) { 320 } 321 322 /** 323 * Same as {@link #onPackageModified(String)}, but this callback 324 * has extras passed in. 325 */ onPackageModifiedWithExtras(@onNull String packageName, Bundle extras)326 public void onPackageModifiedWithExtras(@NonNull String packageName, Bundle extras) { 327 } 328 329 /** 330 * Called when a package in the stopped state is started for some reason. 331 * 332 * @param packageName Name of the package that was unstopped 333 * @param uid UID of the package that was unstopped 334 */ onPackageUnstopped(String packageName, int uid, Bundle extras)335 public void onPackageUnstopped(String packageName, int uid, Bundle extras) { 336 } 337 didSomePackagesChange()338 public boolean didSomePackagesChange() { 339 return mSomePackagesChanged; 340 } 341 isPackageAppearing(String packageName)342 public int isPackageAppearing(String packageName) { 343 if (mAppearingPackages != null) { 344 for (int i=mAppearingPackages.length-1; i>=0; i--) { 345 if (packageName.equals(mAppearingPackages[i])) { 346 return mChangeType; 347 } 348 } 349 } 350 return PACKAGE_UNCHANGED; 351 } 352 anyPackagesAppearing()353 public boolean anyPackagesAppearing() { 354 return mAppearingPackages != null; 355 } 356 357 @UnsupportedAppUsage isPackageDisappearing(String packageName)358 public int isPackageDisappearing(String packageName) { 359 if (mDisappearingPackages != null) { 360 for (int i=mDisappearingPackages.length-1; i>=0; i--) { 361 if (packageName.equals(mDisappearingPackages[i])) { 362 return mChangeType; 363 } 364 } 365 } 366 return PACKAGE_UNCHANGED; 367 } 368 anyPackagesDisappearing()369 public boolean anyPackagesDisappearing() { 370 return mDisappearingPackages != null; 371 } 372 isReplacing()373 public boolean isReplacing() { 374 return mChangeType == PACKAGE_UPDATING; 375 } 376 377 @UnsupportedAppUsage isPackageModified(String packageName)378 public boolean isPackageModified(String packageName) { 379 if (mModifiedPackages != null) { 380 for (int i=mModifiedPackages.length-1; i>=0; i--) { 381 if (packageName.equals(mModifiedPackages[i])) { 382 return true; 383 } 384 } 385 } 386 return false; 387 } 388 isComponentModified(String className)389 public boolean isComponentModified(String className) { 390 if (className == null || mModifiedComponents == null) { 391 return false; 392 } 393 for (int i = mModifiedComponents.length - 1; i >= 0; i--) { 394 if (className.equals(mModifiedComponents[i])) { 395 return true; 396 } 397 } 398 return false; 399 } 400 onSomePackagesChanged()401 public void onSomePackagesChanged() { 402 } 403 onFinishPackageChanges()404 public void onFinishPackageChanges() { 405 } 406 onPackageDataCleared(String packageName, int uid)407 public void onPackageDataCleared(String packageName, int uid) { 408 } 409 410 /** 411 * Callback to indicate the package's state has changed. 412 * @param packageName Name of an installed package 413 * @param uid The UID the package runs under. 414 */ onPackageStateChanged(String packageName, int uid)415 public void onPackageStateChanged(String packageName, int uid) {} 416 getChangingUserId()417 public int getChangingUserId() { 418 return mChangeUserId; 419 } 420 getPackageName(Intent intent)421 String getPackageName(Intent intent) { 422 Uri uri = intent.getData(); 423 String pkg = uri != null ? uri.getSchemeSpecificPart() : null; 424 return pkg; 425 } 426 427 @Override onReceive(Context context, Intent intent)428 public void onReceive(Context context, Intent intent) { 429 doHandlePackageEvent(intent); 430 } 431 432 postHandlePackageEvent(Intent intent)433 private void postHandlePackageEvent(Intent intent) { 434 if (mExecutor != null) { 435 mExecutor.execute(() -> doHandlePackageEvent(intent)); 436 } 437 } 438 439 /** 440 * Handle the package related event 441 * @param intent the intent that contains package related event information 442 */ 443 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) doHandlePackageEvent(Intent intent)444 public final void doHandlePackageEvent(Intent intent) { 445 mChangeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 446 UserHandle.USER_NULL); 447 if (mChangeUserId == UserHandle.USER_NULL) { 448 Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent); 449 return; 450 } 451 onBeginPackageChanges(); 452 453 mDisappearingPackages = mAppearingPackages = null; 454 mSomePackagesChanged = false; 455 mModifiedComponents = null; 456 457 String action = intent.getAction(); 458 if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { 459 String pkg = getPackageName(intent); 460 int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); 461 // We consider something to have changed regardless of whether 462 // this is just an update, because the update is now finished 463 // and the contents of the package may have changed. 464 mSomePackagesChanged = true; 465 if (pkg != null) { 466 mAppearingPackages = mTempArray; 467 mTempArray[0] = pkg; 468 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 469 mModifiedPackages = mTempArray; 470 mChangeType = PACKAGE_UPDATING; 471 onPackageUpdateFinished(pkg, uid); 472 onPackageUpdateFinishedWithExtras(pkg, uid, intent.getExtras()); 473 onPackageModified(pkg); 474 onPackageModifiedWithExtras(pkg, intent.getExtras()); 475 } else { 476 mChangeType = PACKAGE_PERMANENT_CHANGE; 477 onPackageAdded(pkg, uid); 478 onPackageAddedWithExtras(pkg, uid, intent.getExtras()); 479 } 480 onPackageAppearedWithExtras(pkg, intent.getExtras()); 481 onPackageAppeared(pkg, mChangeType); 482 } 483 } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { 484 String pkg = getPackageName(intent); 485 int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); 486 if (pkg != null) { 487 mDisappearingPackages = mTempArray; 488 mTempArray[0] = pkg; 489 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 490 mChangeType = PACKAGE_UPDATING; 491 onPackageUpdateStarted(pkg, uid); 492 onPackageUpdateStartedWithExtras(pkg, uid, intent.getExtras()); 493 if (intent.getBooleanExtra(Intent.EXTRA_ARCHIVAL, false)) { 494 // In case it is a removal event due to archiving, we trigger package 495 // update event to refresh details like icons, title etc. corresponding to 496 // the archived app. 497 onPackageModified(pkg); 498 onPackageModifiedWithExtras(pkg, intent.getExtras()); 499 } 500 } else { 501 mChangeType = PACKAGE_PERMANENT_CHANGE; 502 // We only consider something to have changed if this is 503 // not a replace; for a replace, we just need to consider 504 // it when it is re-added. 505 mSomePackagesChanged = true; 506 onPackageRemoved(pkg, uid); 507 onPackageRemovedWithExtras(pkg, uid, intent.getExtras()); 508 if (intent.getBooleanExtra(Intent.EXTRA_REMOVED_FOR_ALL_USERS, false)) { 509 onPackageRemovedAllUsers(pkg, uid); 510 onPackageRemovedAllUsersWithExtras(pkg, uid, intent.getExtras()); 511 } 512 } 513 onPackageDisappearedWithExtras(pkg, intent.getExtras()); 514 onPackageDisappeared(pkg, mChangeType); 515 } 516 } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) { 517 String pkg = getPackageName(intent); 518 int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); 519 mModifiedComponents = intent.getStringArrayExtra( 520 Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); 521 if (pkg != null) { 522 mModifiedPackages = mTempArray; 523 mTempArray[0] = pkg; 524 mChangeType = PACKAGE_PERMANENT_CHANGE; 525 if (onPackageChanged(pkg, uid, mModifiedComponents)) { 526 mSomePackagesChanged = true; 527 } 528 onPackageChangedWithExtras(pkg, intent.getExtras()); 529 onPackageModified(pkg); 530 onPackageModifiedWithExtras(pkg, intent.getExtras()); 531 } 532 } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) { 533 String pkg = getPackageName(intent); 534 int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); 535 if (pkg != null) { 536 onPackageDataCleared(pkg, uid); 537 } 538 } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { 539 mDisappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 540 mChangeType = PACKAGE_TEMPORARY_CHANGE; 541 boolean canRestart = onHandleForceStop(intent, 542 mDisappearingPackages, 543 intent.getIntExtra(Intent.EXTRA_UID, 0), false, intent.getExtras()); 544 if (canRestart) setResultCode(Activity.RESULT_OK); 545 } else if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) { 546 mDisappearingPackages = new String[] {getPackageName(intent)}; 547 mChangeType = PACKAGE_TEMPORARY_CHANGE; 548 onHandleForceStop(intent, mDisappearingPackages, 549 intent.getIntExtra(Intent.EXTRA_UID, 0), true, intent.getExtras()); 550 } else if (Intent.ACTION_UID_REMOVED.equals(action)) { 551 onUidRemoved(intent.getIntExtra(Intent.EXTRA_UID, 0)); 552 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { 553 String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 554 mAppearingPackages = pkgList; 555 mChangeType = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) 556 ? PACKAGE_UPDATING : PACKAGE_TEMPORARY_CHANGE; 557 mSomePackagesChanged = true; 558 if (pkgList != null) { 559 onPackagesAvailable(pkgList); 560 for (int i=0; i<pkgList.length; i++) { 561 onPackageAppeared(pkgList[i], mChangeType); 562 } 563 } 564 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 565 String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 566 mDisappearingPackages = pkgList; 567 mChangeType = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) 568 ? PACKAGE_UPDATING : PACKAGE_TEMPORARY_CHANGE; 569 mSomePackagesChanged = true; 570 if (pkgList != null) { 571 onPackagesUnavailable(pkgList); 572 for (int i=0; i<pkgList.length; i++) { 573 onPackageDisappeared(pkgList[i], mChangeType); 574 } 575 } 576 } else if (Intent.ACTION_PACKAGES_SUSPENDED.equals(action)) { 577 String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 578 mSomePackagesChanged = true; 579 onPackagesSuspended(pkgList); 580 } else if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(action)) { 581 String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 582 mSomePackagesChanged = true; 583 onPackagesUnsuspended(pkgList); 584 } else if (Intent.ACTION_PACKAGE_UNSTOPPED.equals(action)) { 585 final String pkgName = getPackageName(intent); 586 mAppearingPackages = new String[] {pkgName}; 587 mChangeType = PACKAGE_TEMPORARY_CHANGE; 588 onPackageUnstopped(pkgName, intent.getIntExtra(Intent.EXTRA_UID, 0), 589 intent.getExtras()); 590 } 591 592 if (mSomePackagesChanged) { 593 onSomePackagesChanged(); 594 } 595 596 onFinishPackageChanges(); 597 mChangeUserId = UserHandle.USER_NULL; 598 } 599 600 private static final class PackageMonitorCallback extends IRemoteCallback.Stub { 601 private final WeakReference<PackageMonitor> mMonitorWeakReference; 602 PackageMonitorCallback(PackageMonitor monitor)603 PackageMonitorCallback(PackageMonitor monitor) { 604 mMonitorWeakReference = new WeakReference<>(monitor); 605 } 606 607 @Override sendResult(Bundle data)608 public void sendResult(Bundle data) throws RemoteException { 609 onHandlePackageMonitorCallback(data); 610 } 611 onHandlePackageMonitorCallback(Bundle bundle)612 private void onHandlePackageMonitorCallback(Bundle bundle) { 613 Intent intent = bundle.getParcelable( 614 PackageManager.EXTRA_PACKAGE_MONITOR_CALLBACK_RESULT, Intent.class); 615 if (intent == null) { 616 Log.w(TAG, "No intent is set for PackageMonitorCallback"); 617 return; 618 } 619 PackageMonitor monitor = mMonitorWeakReference.get(); 620 if (monitor != null) { 621 monitor.postHandlePackageEvent(intent); 622 } 623 } 624 } 625 } 626