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