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