PackageMonitor.java revision 80a4af2bbc6af42ae605e454bf89558e564f5244
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 17package com.android.internal.content; 18 19import android.app.Activity; 20import android.content.Context; 21import android.content.Intent; 22import android.content.IntentFilter; 23import android.net.Uri; 24import android.os.Handler; 25import android.os.HandlerThread; 26import android.os.Looper; 27 28import java.util.HashSet; 29 30/** 31 * Helper class for monitoring the state of packages: adding, removing, 32 * updating, and disappearing and reappearing on the SD card. 33 */ 34public abstract class PackageMonitor extends android.content.BroadcastReceiver { 35 static final IntentFilter sPackageFilt = new IntentFilter(); 36 static final IntentFilter sNonDataFilt = new IntentFilter(); 37 static final IntentFilter sExternalFilt = new IntentFilter(); 38 39 static final Object sLock = new Object(); 40 static HandlerThread sBackgroundThread; 41 static Handler sBackgroundHandler; 42 43 static { 44 sPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED); 45 sPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED); 46 sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED); 47 sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 48 sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED); 49 sPackageFilt.addAction(Intent.ACTION_UID_REMOVED); 50 sPackageFilt.addDataScheme("package"); 51 sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED); 52 sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED); 53 sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 54 sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 55 } 56 57 final HashSet<String> mUpdatingPackages = new HashSet<String>(); 58 59 Context mRegisteredContext; 60 Handler mRegisteredHandler; 61 String[] mDisappearingPackages; 62 String[] mAppearingPackages; 63 String[] mModifiedPackages; 64 int mChangeType; 65 boolean mSomePackagesChanged; 66 67 String[] mTempArray = new String[1]; 68 69 public void register(Context context, Looper thread, boolean externalStorage) { 70 if (mRegisteredContext != null) { 71 throw new IllegalStateException("Already registered"); 72 } 73 mRegisteredContext = context; 74 if (thread == null) { 75 synchronized (sLock) { 76 if (sBackgroundThread == null) { 77 sBackgroundThread = new HandlerThread("PackageMonitor", 78 android.os.Process.THREAD_PRIORITY_BACKGROUND); 79 sBackgroundThread.start(); 80 sBackgroundHandler = new Handler(sBackgroundThread.getLooper()); 81 } 82 mRegisteredHandler = sBackgroundHandler; 83 } 84 } else { 85 mRegisteredHandler = new Handler(thread); 86 } 87 context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler); 88 context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler); 89 if (externalStorage) { 90 context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler); 91 } 92 } 93 94 public Handler getRegisteredHandler() { 95 return mRegisteredHandler; 96 } 97 98 public void unregister() { 99 if (mRegisteredContext == null) { 100 throw new IllegalStateException("Not registered"); 101 } 102 mRegisteredContext.unregisterReceiver(this); 103 mRegisteredContext = null; 104 } 105 106 //not yet implemented 107 boolean isPackageUpdating(String packageName) { 108 synchronized (mUpdatingPackages) { 109 return mUpdatingPackages.contains(packageName); 110 } 111 } 112 113 public void onBeginPackageChanges() { 114 } 115 116 /** 117 * Called when a package is really added (and not replaced). 118 */ 119 public void onPackageAdded(String packageName, int uid) { 120 } 121 122 /** 123 * Called when a package is really removed (and not replaced). 124 */ 125 public void onPackageRemoved(String packageName, int uid) { 126 } 127 128 public void onPackageUpdateStarted(String packageName, int uid) { 129 } 130 131 public void onPackageUpdateFinished(String packageName, int uid) { 132 } 133 134 public void onPackageChanged(String packageName, int uid, String[] components) { 135 } 136 137 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 138 return false; 139 } 140 141 public void onHandleUserStop(Intent intent, int userHandle) { 142 } 143 144 public void onUidRemoved(int uid) { 145 } 146 147 public void onPackagesAvailable(String[] packages) { 148 } 149 150 public void onPackagesUnavailable(String[] packages) { 151 } 152 153 public static final int PACKAGE_UNCHANGED = 0; 154 public static final int PACKAGE_UPDATING = 1; 155 public static final int PACKAGE_TEMPORARY_CHANGE = 2; 156 public static final int PACKAGE_PERMANENT_CHANGE = 3; 157 158 /** 159 * Called when a package disappears for any reason. 160 */ 161 public void onPackageDisappeared(String packageName, int reason) { 162 } 163 164 /** 165 * Called when a package appears for any reason. 166 */ 167 public void onPackageAppeared(String packageName, int reason) { 168 } 169 170 public void onPackageModified(String packageName) { 171 } 172 173 public boolean didSomePackagesChange() { 174 return mSomePackagesChanged; 175 } 176 177 public int isPackageAppearing(String packageName) { 178 if (mAppearingPackages != null) { 179 for (int i=mAppearingPackages.length-1; i>=0; i--) { 180 if (packageName.equals(mAppearingPackages[i])) { 181 return mChangeType; 182 } 183 } 184 } 185 return PACKAGE_UNCHANGED; 186 } 187 188 public boolean anyPackagesAppearing() { 189 return mAppearingPackages != null; 190 } 191 192 public int isPackageDisappearing(String packageName) { 193 if (mDisappearingPackages != null) { 194 for (int i=mDisappearingPackages.length-1; i>=0; i--) { 195 if (packageName.equals(mDisappearingPackages[i])) { 196 return mChangeType; 197 } 198 } 199 } 200 return PACKAGE_UNCHANGED; 201 } 202 203 public boolean anyPackagesDisappearing() { 204 return mDisappearingPackages != null; 205 } 206 207 public boolean isPackageModified(String packageName) { 208 if (mModifiedPackages != null) { 209 for (int i=mModifiedPackages.length-1; i>=0; i--) { 210 if (packageName.equals(mModifiedPackages[i])) { 211 return true; 212 } 213 } 214 } 215 return false; 216 } 217 218 public void onSomePackagesChanged() { 219 } 220 221 public void onFinishPackageChanges() { 222 } 223 224 String getPackageName(Intent intent) { 225 Uri uri = intent.getData(); 226 String pkg = uri != null ? uri.getSchemeSpecificPart() : null; 227 return pkg; 228 } 229 230 @Override 231 public void onReceive(Context context, Intent intent) { 232 onBeginPackageChanges(); 233 234 mDisappearingPackages = mAppearingPackages = null; 235 mSomePackagesChanged = false; 236 237 String action = intent.getAction(); 238 if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { 239 String pkg = getPackageName(intent); 240 int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); 241 // We consider something to have changed regardless of whether 242 // this is just an update, because the update is now finished 243 // and the contents of the package may have changed. 244 mSomePackagesChanged = true; 245 if (pkg != null) { 246 mAppearingPackages = mTempArray; 247 mTempArray[0] = pkg; 248 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 249 mModifiedPackages = mTempArray; 250 mChangeType = PACKAGE_UPDATING; 251 onPackageUpdateFinished(pkg, uid); 252 onPackageModified(pkg); 253 } else { 254 mChangeType = PACKAGE_PERMANENT_CHANGE; 255 onPackageAdded(pkg, uid); 256 } 257 onPackageAppeared(pkg, mChangeType); 258 if (mChangeType == PACKAGE_UPDATING) { 259 synchronized (mUpdatingPackages) { 260 mUpdatingPackages.remove(pkg); 261 } 262 } 263 } 264 } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { 265 String pkg = getPackageName(intent); 266 int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); 267 if (pkg != null) { 268 mDisappearingPackages = mTempArray; 269 mTempArray[0] = pkg; 270 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 271 mChangeType = PACKAGE_UPDATING; 272 synchronized (mUpdatingPackages) { 273 //not used for now 274 //mUpdatingPackages.add(pkg); 275 } 276 onPackageUpdateStarted(pkg, uid); 277 } else { 278 mChangeType = PACKAGE_PERMANENT_CHANGE; 279 // We only consider something to have changed if this is 280 // not a replace; for a replace, we just need to consider 281 // it when it is re-added. 282 mSomePackagesChanged = true; 283 onPackageRemoved(pkg, uid); 284 } 285 onPackageDisappeared(pkg, mChangeType); 286 } 287 } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) { 288 String pkg = getPackageName(intent); 289 int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); 290 String[] components = intent.getStringArrayExtra( 291 Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); 292 if (pkg != null) { 293 mModifiedPackages = mTempArray; 294 mTempArray[0] = pkg; 295 onPackageChanged(pkg, uid, components); 296 // XXX Don't want this to always cause mSomePackagesChanged, 297 // since it can happen a fair amount. 298 onPackageModified(pkg); 299 } 300 } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { 301 mDisappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 302 mChangeType = PACKAGE_TEMPORARY_CHANGE; 303 boolean canRestart = onHandleForceStop(intent, 304 mDisappearingPackages, 305 intent.getIntExtra(Intent.EXTRA_UID, 0), false); 306 if (canRestart) setResultCode(Activity.RESULT_OK); 307 } else if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) { 308 mDisappearingPackages = new String[] {getPackageName(intent)}; 309 mChangeType = PACKAGE_TEMPORARY_CHANGE; 310 onHandleForceStop(intent, mDisappearingPackages, 311 intent.getIntExtra(Intent.EXTRA_UID, 0), true); 312 } else if (Intent.ACTION_UID_REMOVED.equals(action)) { 313 onUidRemoved(intent.getIntExtra(Intent.EXTRA_UID, 0)); 314 } else if (Intent.ACTION_USER_STOPPED.equals(action)) { 315 if (intent.hasExtra(Intent.EXTRA_USER_HANDLE)) { 316 onHandleUserStop(intent, intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 317 } 318 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { 319 String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 320 mAppearingPackages = pkgList; 321 mChangeType = PACKAGE_TEMPORARY_CHANGE; 322 mSomePackagesChanged = true; 323 if (pkgList != null) { 324 onPackagesAvailable(pkgList); 325 for (int i=0; i<pkgList.length; i++) { 326 onPackageAppeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE); 327 } 328 } 329 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 330 String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 331 mDisappearingPackages = pkgList; 332 mChangeType = PACKAGE_TEMPORARY_CHANGE; 333 mSomePackagesChanged = true; 334 if (pkgList != null) { 335 onPackagesUnavailable(pkgList); 336 for (int i=0; i<pkgList.length; i++) { 337 onPackageDisappeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE); 338 } 339 } 340 } 341 342 if (mSomePackagesChanged) { 343 onSomePackagesChanged(); 344 } 345 346 onFinishPackageChanges(); 347 } 348} 349