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