Home | History | Annotate | Download | only in content
      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 
     72     public void register(Context context, Looper thread, boolean externalStorage) {
     73         register(context, thread, null, externalStorage);
     74     }
     75 
     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 
     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 
    105     public Handler getRegisteredHandler() {
    106         return mRegisteredHandler;
    107     }
    108 
    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
    118     boolean isPackageUpdating(String packageName) {
    119         synchronized (mUpdatingPackages) {
    120             return mUpdatingPackages.contains(packageName);
    121         }
    122     }
    123 
    124     public void onBeginPackageChanges() {
    125     }
    126 
    127     /**
    128      * Called when a package is really added (and not replaced).
    129      */
    130     public void onPackageAdded(String packageName, int uid) {
    131     }
    132 
    133     /**
    134      * Called when a package is really removed (and not replaced).
    135      */
    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      */
    143     public void onPackageRemovedAllUsers(String packageName, int uid) {
    144     }
    145 
    146     public void onPackageUpdateStarted(String packageName, int uid) {
    147     }
    148 
    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      */
    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 
    180     public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
    181         return false;
    182     }
    183 
    184     public void onHandleUserStop(Intent intent, int userHandle) {
    185     }
    186 
    187     public void onUidRemoved(int uid) {
    188     }
    189 
    190     public void onPackagesAvailable(String[] packages) {
    191     }
    192 
    193     public void onPackagesUnavailable(String[] packages) {
    194     }
    195 
    196     public void onPackagesSuspended(String[] packages) {
    197     }
    198 
    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      */
    210     public void onPackageDisappeared(String packageName, int reason) {
    211     }
    212 
    213     /**
    214      * Called when a package appears for any reason.
    215      */
    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      */
    222     public void onPackageModified(String packageName) {
    223     }
    224 
    225     public boolean didSomePackagesChange() {
    226         return mSomePackagesChanged;
    227     }
    228 
    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 
    240     public boolean anyPackagesAppearing() {
    241         return mAppearingPackages != null;
    242     }
    243 
    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 
    255     public boolean anyPackagesDisappearing() {
    256         return mDisappearingPackages != null;
    257     }
    258 
    259     public boolean isReplacing() {
    260         return mChangeType == PACKAGE_UPDATING;
    261     }
    262 
    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 
    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 
    286     public void onSomePackagesChanged() {
    287     }
    288 
    289     public void onFinishPackageChanges() {
    290     }
    291 
    292     public void onPackageDataCleared(String packageName, int uid) {
    293     }
    294 
    295     public int getChangingUserId() {
    296         return mChangeUserId;
    297     }
    298 
    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
    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