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.net.Uri; 26 import android.os.Handler; 27 import android.os.Looper; 28 import android.os.UserHandle; 29 import android.util.Slog; 30 31 import com.android.internal.os.BackgroundThread; 32 33 import java.util.HashSet; 34 import java.util.Objects; 35 36 /** 37 * Helper class for monitoring the state of packages: adding, removing, 38 * updating, and disappearing and reappearing on the SD card. 39 */ 40 public abstract class PackageMonitor extends android.content.BroadcastReceiver { 41 static final String TAG = "PackageMonitor"; 42 static final IntentFilter sPackageFilt = new IntentFilter(); 43 static final IntentFilter sNonDataFilt = new IntentFilter(); 44 static final IntentFilter sExternalFilt = new IntentFilter(); 45 46 static { 47 sPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED); 48 sPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED); 49 sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED); 50 sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 51 sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED); 52 sPackageFilt.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); 53 sPackageFilt.addDataScheme("package"); 54 sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED); 55 sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED); 56 sNonDataFilt.addAction(Intent.ACTION_PACKAGES_SUSPENDED); 57 sNonDataFilt.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); 58 sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 59 sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 60 } 61 62 final HashSet<String> mUpdatingPackages = new HashSet<String>(); 63 64 Context mRegisteredContext; 65 Handler mRegisteredHandler; 66 String[] mDisappearingPackages; 67 String[] mAppearingPackages; 68 String[] mModifiedPackages; 69 int mChangeType; 70 int mChangeUserId = UserHandle.USER_NULL; 71 boolean mSomePackagesChanged; 72 String[] mModifiedComponents; 73 74 String[] mTempArray = new String[1]; 75 76 @UnsupportedAppUsage PackageMonitor()77 public PackageMonitor() { 78 } 79 80 @UnsupportedAppUsage register(Context context, Looper thread, boolean externalStorage)81 public void register(Context context, Looper thread, boolean externalStorage) { 82 register(context, thread, null, externalStorage); 83 } 84 85 @UnsupportedAppUsage register(Context context, Looper thread, UserHandle user, boolean externalStorage)86 public void register(Context context, Looper thread, UserHandle user, 87 boolean externalStorage) { 88 register(context, user, externalStorage, 89 (thread == null) ? BackgroundThread.getHandler() : new Handler(thread)); 90 } 91 register(Context context, UserHandle user, boolean externalStorage, Handler handler)92 public void register(Context context, UserHandle user, 93 boolean externalStorage, Handler handler) { 94 if (mRegisteredContext != null) { 95 throw new IllegalStateException("Already registered"); 96 } 97 mRegisteredContext = context; 98 mRegisteredHandler = Objects.requireNonNull(handler); 99 if (user != null) { 100 context.registerReceiverAsUser(this, user, sPackageFilt, null, mRegisteredHandler); 101 context.registerReceiverAsUser(this, user, sNonDataFilt, null, mRegisteredHandler); 102 if (externalStorage) { 103 context.registerReceiverAsUser(this, user, sExternalFilt, null, 104 mRegisteredHandler); 105 } 106 } else { 107 context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler); 108 context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler); 109 if (externalStorage) { 110 context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler); 111 } 112 } 113 } 114 getRegisteredHandler()115 public Handler getRegisteredHandler() { 116 return mRegisteredHandler; 117 } 118 119 @UnsupportedAppUsage unregister()120 public void unregister() { 121 if (mRegisteredContext == null) { 122 throw new IllegalStateException("Not registered"); 123 } 124 mRegisteredContext.unregisterReceiver(this); 125 mRegisteredContext = null; 126 } 127 128 //not yet implemented isPackageUpdating(String packageName)129 boolean isPackageUpdating(String packageName) { 130 synchronized (mUpdatingPackages) { 131 return mUpdatingPackages.contains(packageName); 132 } 133 } 134 onBeginPackageChanges()135 public void onBeginPackageChanges() { 136 } 137 138 /** 139 * Called when a package is really added (and not replaced). 140 */ onPackageAdded(String packageName, int uid)141 public void onPackageAdded(String packageName, int uid) { 142 } 143 144 /** 145 * Called when a package is really removed (and not replaced). 146 */ 147 @UnsupportedAppUsage onPackageRemoved(String packageName, int uid)148 public void onPackageRemoved(String packageName, int uid) { 149 } 150 151 /** 152 * Called when a package is really removed (and not replaced) for 153 * all users on the device. 154 */ onPackageRemovedAllUsers(String packageName, int uid)155 public void onPackageRemovedAllUsers(String packageName, int uid) { 156 } 157 onPackageUpdateStarted(String packageName, int uid)158 public void onPackageUpdateStarted(String packageName, int uid) { 159 } 160 onPackageUpdateFinished(String packageName, int uid)161 public void onPackageUpdateFinished(String packageName, int uid) { 162 } 163 164 /** 165 * Direct reflection of {@link Intent#ACTION_PACKAGE_CHANGED 166 * Intent.ACTION_PACKAGE_CHANGED} being received, informing you of 167 * changes to the enabled/disabled state of components in a package 168 * and/or of the overall package. 169 * 170 * @param packageName The name of the package that is changing. 171 * @param uid The user ID the package runs under. 172 * @param components Any components in the package that are changing. If 173 * the overall package is changing, this will contain an entry of the 174 * package name itself. 175 * @return Return true to indicate you care about this change, which will 176 * result in {@link #onSomePackagesChanged()} being called later. If you 177 * return false, no further callbacks will happen about this change. The 178 * default implementation returns true if this is a change to the entire 179 * package. 180 */ 181 @UnsupportedAppUsage onPackageChanged(String packageName, int uid, String[] components)182 public boolean onPackageChanged(String packageName, int uid, String[] components) { 183 if (components != null) { 184 for (String name : components) { 185 if (packageName.equals(name)) { 186 return true; 187 } 188 } 189 } 190 return false; 191 } 192 onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit)193 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 194 return false; 195 } 196 onHandleUserStop(Intent intent, int userHandle)197 public void onHandleUserStop(Intent intent, int userHandle) { 198 } 199 onUidRemoved(int uid)200 public void onUidRemoved(int uid) { 201 } 202 onPackagesAvailable(String[] packages)203 public void onPackagesAvailable(String[] packages) { 204 } 205 onPackagesUnavailable(String[] packages)206 public void onPackagesUnavailable(String[] packages) { 207 } 208 onPackagesSuspended(String[] packages)209 public void onPackagesSuspended(String[] packages) { 210 } 211 onPackagesUnsuspended(String[] packages)212 public void onPackagesUnsuspended(String[] packages) { 213 } 214 215 public static final int PACKAGE_UNCHANGED = 0; 216 public static final int PACKAGE_UPDATING = 1; 217 public static final int PACKAGE_TEMPORARY_CHANGE = 2; 218 public static final int PACKAGE_PERMANENT_CHANGE = 3; 219 220 /** 221 * Called when a package disappears for any reason. 222 */ onPackageDisappeared(String packageName, int reason)223 public void onPackageDisappeared(String packageName, int reason) { 224 } 225 226 /** 227 * Called when a package appears for any reason. 228 */ onPackageAppeared(String packageName, int reason)229 public void onPackageAppeared(String packageName, int reason) { 230 } 231 232 /** 233 * Called when an existing package is updated or its disabled state changes. 234 */ onPackageModified(@onNull String packageName)235 public void onPackageModified(@NonNull String packageName) { 236 } 237 didSomePackagesChange()238 public boolean didSomePackagesChange() { 239 return mSomePackagesChanged; 240 } 241 isPackageAppearing(String packageName)242 public int isPackageAppearing(String packageName) { 243 if (mAppearingPackages != null) { 244 for (int i=mAppearingPackages.length-1; i>=0; i--) { 245 if (packageName.equals(mAppearingPackages[i])) { 246 return mChangeType; 247 } 248 } 249 } 250 return PACKAGE_UNCHANGED; 251 } 252 anyPackagesAppearing()253 public boolean anyPackagesAppearing() { 254 return mAppearingPackages != null; 255 } 256 257 @UnsupportedAppUsage isPackageDisappearing(String packageName)258 public int isPackageDisappearing(String packageName) { 259 if (mDisappearingPackages != null) { 260 for (int i=mDisappearingPackages.length-1; i>=0; i--) { 261 if (packageName.equals(mDisappearingPackages[i])) { 262 return mChangeType; 263 } 264 } 265 } 266 return PACKAGE_UNCHANGED; 267 } 268 anyPackagesDisappearing()269 public boolean anyPackagesDisappearing() { 270 return mDisappearingPackages != null; 271 } 272 isReplacing()273 public boolean isReplacing() { 274 return mChangeType == PACKAGE_UPDATING; 275 } 276 277 @UnsupportedAppUsage isPackageModified(String packageName)278 public boolean isPackageModified(String packageName) { 279 if (mModifiedPackages != null) { 280 for (int i=mModifiedPackages.length-1; i>=0; i--) { 281 if (packageName.equals(mModifiedPackages[i])) { 282 return true; 283 } 284 } 285 } 286 return false; 287 } 288 isComponentModified(String className)289 public boolean isComponentModified(String className) { 290 if (className == null || mModifiedComponents == null) { 291 return false; 292 } 293 for (int i = mModifiedComponents.length - 1; i >= 0; i--) { 294 if (className.equals(mModifiedComponents[i])) { 295 return true; 296 } 297 } 298 return false; 299 } 300 onSomePackagesChanged()301 public void onSomePackagesChanged() { 302 } 303 onFinishPackageChanges()304 public void onFinishPackageChanges() { 305 } 306 onPackageDataCleared(String packageName, int uid)307 public void onPackageDataCleared(String packageName, int uid) { 308 } 309 310 /** 311 * Callback to indicate the package's state has changed. 312 * @param packageName Name of an installed package 313 * @param uid The UID the package runs under. 314 */ onPackageStateChanged(String packageName, int uid)315 public void onPackageStateChanged(String packageName, int uid) {} 316 getChangingUserId()317 public int getChangingUserId() { 318 return mChangeUserId; 319 } 320 getPackageName(Intent intent)321 String getPackageName(Intent intent) { 322 Uri uri = intent.getData(); 323 String pkg = uri != null ? uri.getSchemeSpecificPart() : null; 324 return pkg; 325 } 326 327 @Override onReceive(Context context, Intent intent)328 public void onReceive(Context context, Intent intent) { 329 mChangeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 330 UserHandle.USER_NULL); 331 if (mChangeUserId == UserHandle.USER_NULL) { 332 Slog.w("PackageMonitor", "Intent broadcast does not contain user handle: " + intent); 333 return; 334 } 335 onBeginPackageChanges(); 336 337 mDisappearingPackages = mAppearingPackages = null; 338 mSomePackagesChanged = false; 339 mModifiedComponents = null; 340 341 String action = intent.getAction(); 342 if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { 343 String pkg = getPackageName(intent); 344 int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); 345 // We consider something to have changed regardless of whether 346 // this is just an update, because the update is now finished 347 // and the contents of the package may have changed. 348 mSomePackagesChanged = true; 349 if (pkg != null) { 350 mAppearingPackages = mTempArray; 351 mTempArray[0] = pkg; 352 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 353 mModifiedPackages = mTempArray; 354 mChangeType = PACKAGE_UPDATING; 355 onPackageUpdateFinished(pkg, uid); 356 onPackageModified(pkg); 357 } else { 358 mChangeType = PACKAGE_PERMANENT_CHANGE; 359 onPackageAdded(pkg, uid); 360 } 361 onPackageAppeared(pkg, mChangeType); 362 if (mChangeType == PACKAGE_UPDATING) { 363 synchronized (mUpdatingPackages) { 364 mUpdatingPackages.remove(pkg); 365 } 366 } 367 } 368 } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { 369 String pkg = getPackageName(intent); 370 int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); 371 if (pkg != null) { 372 mDisappearingPackages = mTempArray; 373 mTempArray[0] = pkg; 374 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 375 mChangeType = PACKAGE_UPDATING; 376 synchronized (mUpdatingPackages) { 377 //not used for now 378 //mUpdatingPackages.add(pkg); 379 } 380 onPackageUpdateStarted(pkg, uid); 381 } else { 382 mChangeType = PACKAGE_PERMANENT_CHANGE; 383 // We only consider something to have changed if this is 384 // not a replace; for a replace, we just need to consider 385 // it when it is re-added. 386 mSomePackagesChanged = true; 387 onPackageRemoved(pkg, uid); 388 if (intent.getBooleanExtra(Intent.EXTRA_REMOVED_FOR_ALL_USERS, false)) { 389 onPackageRemovedAllUsers(pkg, uid); 390 } 391 } 392 onPackageDisappeared(pkg, mChangeType); 393 } 394 } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) { 395 String pkg = getPackageName(intent); 396 int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); 397 mModifiedComponents = intent.getStringArrayExtra( 398 Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); 399 if (pkg != null) { 400 mModifiedPackages = mTempArray; 401 mTempArray[0] = pkg; 402 mChangeType = PACKAGE_PERMANENT_CHANGE; 403 if (onPackageChanged(pkg, uid, mModifiedComponents)) { 404 mSomePackagesChanged = true; 405 } 406 onPackageModified(pkg); 407 } 408 } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) { 409 String pkg = getPackageName(intent); 410 int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); 411 if (pkg != null) { 412 onPackageDataCleared(pkg, uid); 413 } 414 } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { 415 mDisappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 416 mChangeType = PACKAGE_TEMPORARY_CHANGE; 417 boolean canRestart = onHandleForceStop(intent, 418 mDisappearingPackages, 419 intent.getIntExtra(Intent.EXTRA_UID, 0), false); 420 if (canRestart) setResultCode(Activity.RESULT_OK); 421 } else if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) { 422 mDisappearingPackages = new String[] {getPackageName(intent)}; 423 mChangeType = PACKAGE_TEMPORARY_CHANGE; 424 onHandleForceStop(intent, mDisappearingPackages, 425 intent.getIntExtra(Intent.EXTRA_UID, 0), true); 426 } else if (Intent.ACTION_UID_REMOVED.equals(action)) { 427 onUidRemoved(intent.getIntExtra(Intent.EXTRA_UID, 0)); 428 } else if (Intent.ACTION_USER_STOPPED.equals(action)) { 429 if (intent.hasExtra(Intent.EXTRA_USER_HANDLE)) { 430 onHandleUserStop(intent, intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 431 } 432 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { 433 String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 434 mAppearingPackages = pkgList; 435 mChangeType = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) 436 ? PACKAGE_UPDATING : PACKAGE_TEMPORARY_CHANGE; 437 mSomePackagesChanged = true; 438 if (pkgList != null) { 439 onPackagesAvailable(pkgList); 440 for (int i=0; i<pkgList.length; i++) { 441 onPackageAppeared(pkgList[i], mChangeType); 442 } 443 } 444 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 445 String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 446 mDisappearingPackages = pkgList; 447 mChangeType = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) 448 ? PACKAGE_UPDATING : PACKAGE_TEMPORARY_CHANGE; 449 mSomePackagesChanged = true; 450 if (pkgList != null) { 451 onPackagesUnavailable(pkgList); 452 for (int i=0; i<pkgList.length; i++) { 453 onPackageDisappeared(pkgList[i], mChangeType); 454 } 455 } 456 } else if (Intent.ACTION_PACKAGES_SUSPENDED.equals(action)) { 457 String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 458 mSomePackagesChanged = true; 459 onPackagesSuspended(pkgList); 460 } else if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(action)) { 461 String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 462 mSomePackagesChanged = true; 463 onPackagesUnsuspended(pkgList); 464 } 465 466 if (mSomePackagesChanged) { 467 onSomePackagesChanged(); 468 } 469 470 onFinishPackageChanges(); 471 mChangeUserId = UserHandle.USER_NULL; 472 } 473 } 474