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