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