blob: 7e7cd7a8dcf2a64404294f680233047e4742a1bc [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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 android.app;
18
svetoslavganov75986cf2009-05-14 22:28:01 -070019import com.android.internal.policy.PolicyManager;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080020import com.android.internal.util.XmlUtils;
svetoslavganov75986cf2009-05-14 22:28:01 -070021import com.google.android.collect.Maps;
22
23import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.BroadcastReceiver;
26import android.content.ComponentName;
27import android.content.ContentResolver;
28import android.content.Context;
29import android.content.ContextWrapper;
30import android.content.IContentProvider;
31import android.content.Intent;
32import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070033import android.content.IIntentReceiver;
34import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.content.ReceiverCallNotAllowedException;
36import android.content.ServiceConnection;
37import android.content.SharedPreferences;
38import android.content.pm.ActivityInfo;
39import android.content.pm.ApplicationInfo;
40import android.content.pm.ComponentInfo;
Dianne Hackborn49237342009-08-27 20:08:01 -070041import android.content.pm.FeatureInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.content.pm.IPackageDataObserver;
43import android.content.pm.IPackageDeleteObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.content.pm.IPackageInstallObserver;
Suchi Amalapurapu8946dd32010-02-19 09:19:34 -080045import android.content.pm.IPackageMoveObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.pm.IPackageManager;
svetoslavganov75986cf2009-05-14 22:28:01 -070047import android.content.pm.IPackageStatsObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.pm.InstrumentationInfo;
49import android.content.pm.PackageInfo;
50import android.content.pm.PackageManager;
51import android.content.pm.PermissionGroupInfo;
52import android.content.pm.PermissionInfo;
53import android.content.pm.ProviderInfo;
54import android.content.pm.ResolveInfo;
55import android.content.pm.ServiceInfo;
Suchi Amalapurapu117818e2010-02-09 03:45:40 -080056import android.content.pm.PackageParser.Package;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.content.res.AssetManager;
58import android.content.res.Resources;
59import android.content.res.XmlResourceParser;
60import android.database.sqlite.SQLiteDatabase;
61import android.database.sqlite.SQLiteDatabase.CursorFactory;
62import android.graphics.Bitmap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.graphics.drawable.Drawable;
64import android.hardware.SensorManager;
65import android.location.ILocationManager;
66import android.location.LocationManager;
67import android.media.AudioManager;
68import android.net.ConnectivityManager;
69import android.net.IConnectivityManager;
Irfan Sheriffc9b68512010-04-08 14:12:33 -070070import android.net.ThrottleManager;
71import android.net.IThrottleManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.net.Uri;
73import android.net.wifi.IWifiManager;
74import android.net.wifi.WifiManager;
Nick Pelly50b4d8f2010-12-07 22:40:28 -080075import android.nfc.NfcManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import android.os.Binder;
77import android.os.Bundle;
Dan Egnorf18a01c2009-11-12 11:32:50 -080078import android.os.DropBoxManager;
Oscar Montemayor539d3c42010-01-29 15:27:00 -080079import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import android.os.FileUtils;
81import android.os.Handler;
82import android.os.IBinder;
83import android.os.IPowerManager;
svetoslavganov75986cf2009-05-14 22:28:01 -070084import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.PowerManager;
86import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -070087import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.os.ServiceManager;
Oscar Montemayor539d3c42010-01-29 15:27:00 -080089import android.os.StatFs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.os.Vibrator;
91import android.os.FileUtils.FileStatus;
San Mehatb1043402010-02-05 08:26:50 -080092import android.os.storage.StorageManager;
Suchi Amalapurapu117818e2010-02-09 03:45:40 -080093import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.telephony.TelephonyManager;
95import android.text.ClipboardManager;
96import android.util.AndroidRuntimeException;
97import android.util.Log;
98import android.view.ContextThemeWrapper;
99import android.view.LayoutInflater;
100import android.view.WindowManagerImpl;
svetoslavganov75986cf2009-05-14 22:28:01 -0700101import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102import android.view.inputmethod.InputMethodManager;
Fred Quintana60307342009-03-24 22:48:12 -0700103import android.accounts.AccountManager;
104import android.accounts.IAccountManager;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800105import android.app.admin.DevicePolicyManager;
Dan Egnorf18a01c2009-11-12 11:32:50 -0800106import com.android.internal.os.IDropBoxManagerService;
Dan Egnor95240272009-10-27 18:23:39 -0700107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108import java.io.File;
109import java.io.FileInputStream;
110import java.io.FileNotFoundException;
111import java.io.FileOutputStream;
112import java.io.IOException;
113import java.io.InputStream;
114import java.lang.ref.WeakReference;
115import java.util.ArrayList;
116import java.util.HashMap;
svetoslavganov75986cf2009-05-14 22:28:01 -0700117import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118import java.util.Iterator;
119import java.util.List;
120import java.util.Map;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700121import java.util.Map.Entry;
The Android Open Source Project10592532009-03-18 17:39:46 -0700122import java.util.Set;
svetoslavganov75986cf2009-05-14 22:28:01 -0700123import java.util.WeakHashMap;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700124import java.util.concurrent.CountDownLatch;
125import java.util.concurrent.ExecutorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127class ReceiverRestrictedContext extends ContextWrapper {
128 ReceiverRestrictedContext(Context base) {
129 super(base);
130 }
131
132 @Override
133 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
134 return registerReceiver(receiver, filter, null, null);
135 }
136
137 @Override
138 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
139 String broadcastPermission, Handler scheduler) {
140 throw new ReceiverCallNotAllowedException(
141 "IntentReceiver components are not allowed to register to receive intents");
142 //ex.fillInStackTrace();
143 //Log.e("IntentReceiver", ex.getMessage(), ex);
144 //return mContext.registerReceiver(receiver, filter, broadcastPermission,
145 // scheduler);
146 }
147
148 @Override
149 public boolean bindService(Intent service, ServiceConnection conn, int flags) {
150 throw new ReceiverCallNotAllowedException(
151 "IntentReceiver components are not allowed to bind to services");
152 //ex.fillInStackTrace();
153 //Log.e("IntentReceiver", ex.getMessage(), ex);
154 //return mContext.bindService(service, interfaceName, conn, flags);
155 }
156}
157
158/**
Dianne Hackborn21556372010-02-04 16:34:40 -0800159 * Common implementation of Context API, which provides the base
160 * context object for Activity and other application components.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 */
Dianne Hackborn21556372010-02-04 16:34:40 -0800162class ContextImpl extends Context {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 private final static String TAG = "ApplicationContext";
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700164 private final static boolean DEBUG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 private final static boolean DEBUG_ICONS = false;
166
167 private static final Object sSync = new Object();
168 private static AlarmManager sAlarmManager;
169 private static PowerManager sPowerManager;
170 private static ConnectivityManager sConnectivityManager;
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700171 private static ThrottleManager sThrottleManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 private static WifiManager sWifiManager;
173 private static LocationManager sLocationManager;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700174 private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
175 new HashMap<String, SharedPreferencesImpl>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
177 private AudioManager mAudioManager;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700178 /*package*/ LoadedApk mPackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 private Resources mResources;
180 /*package*/ ActivityThread mMainThread;
181 private Context mOuterContext;
182 private IBinder mActivityToken = null;
183 private ApplicationContentResolver mContentResolver;
184 private int mThemeResource = 0;
185 private Resources.Theme mTheme = null;
186 private PackageManager mPackageManager;
187 private NotificationManager mNotificationManager = null;
188 private ActivityManager mActivityManager = null;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700189 private WallpaperManager mWallpaperManager = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 private Context mReceiverRestrictedContext = null;
191 private SearchManager mSearchManager = null;
192 private SensorManager mSensorManager = null;
San Mehatc9d81752010-02-01 10:23:27 -0800193 private StorageManager mStorageManager = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 private Vibrator mVibrator = null;
195 private LayoutInflater mLayoutInflater = null;
196 private StatusBarManager mStatusBarManager = null;
197 private TelephonyManager mTelephonyManager = null;
198 private ClipboardManager mClipboardManager = null;
Romain Guy870e09f2009-07-06 16:35:25 -0700199 private boolean mRestricted;
Fred Quintanae00a3112009-09-22 15:13:30 -0700200 private AccountManager mAccountManager; // protected by mSync
Dan Egnorf18a01c2009-11-12 11:32:50 -0800201 private DropBoxManager mDropBoxManager = null;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800202 private DevicePolicyManager mDevicePolicyManager = null;
Tobias Haamel53332882010-02-18 16:15:43 -0800203 private UiModeManager mUiModeManager = null;
Steve Howarda2709362010-07-02 17:12:48 -0700204 private DownloadManager mDownloadManager = null;
Nick Pelly50b4d8f2010-12-07 22:40:28 -0800205 private NfcManager mNfcManager = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206
207 private final Object mSync = new Object();
208
209 private File mDatabasesDir;
210 private File mPreferencesDir;
211 private File mFilesDir;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 private File mCacheDir;
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800213 private File mExternalFilesDir;
214 private File mExternalCacheDir;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 private static long sInstanceCount = 0;
217
218 private static final String[] EMPTY_FILE_LIST = {};
219
Carl Shapiro82fe5642010-02-24 00:14:23 -0800220 // For debug only
221 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 @Override
223 protected void finalize() throws Throwable {
224 super.finalize();
225 --sInstanceCount;
226 }
Carl Shapiro82fe5642010-02-24 00:14:23 -0800227 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228
229 public static long getInstanceCount() {
230 return sInstanceCount;
231 }
232
233 @Override
234 public AssetManager getAssets() {
235 return mResources.getAssets();
236 }
237
238 @Override
239 public Resources getResources() {
240 return mResources;
241 }
242
243 @Override
244 public PackageManager getPackageManager() {
245 if (mPackageManager != null) {
246 return mPackageManager;
247 }
248
249 IPackageManager pm = ActivityThread.getPackageManager();
250 if (pm != null) {
251 // Doesn't matter if we make more than one instance.
252 return (mPackageManager = new ApplicationPackageManager(this, pm));
253 }
254
255 return null;
256 }
257
258 @Override
259 public ContentResolver getContentResolver() {
260 return mContentResolver;
261 }
262
263 @Override
264 public Looper getMainLooper() {
265 return mMainThread.getLooper();
266 }
267
268 @Override
269 public Context getApplicationContext() {
Christopher Tateeb9e9ec2010-03-23 17:14:36 -0700270 return (mPackageInfo != null) ?
271 mPackageInfo.getApplication() : mMainThread.getApplication();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 }
273
274 @Override
275 public void setTheme(int resid) {
276 mThemeResource = resid;
277 }
278
279 @Override
280 public Resources.Theme getTheme() {
281 if (mTheme == null) {
282 if (mThemeResource == 0) {
283 mThemeResource = com.android.internal.R.style.Theme;
284 }
285 mTheme = mResources.newTheme();
286 mTheme.applyStyle(mThemeResource, true);
287 }
288 return mTheme;
289 }
290
291 @Override
292 public ClassLoader getClassLoader() {
293 return mPackageInfo != null ?
294 mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader();
295 }
296
297 @Override
298 public String getPackageName() {
299 if (mPackageInfo != null) {
300 return mPackageInfo.getPackageName();
301 }
302 throw new RuntimeException("Not supported in system context");
303 }
304
305 @Override
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700306 public ApplicationInfo getApplicationInfo() {
307 if (mPackageInfo != null) {
308 return mPackageInfo.getApplicationInfo();
309 }
310 throw new RuntimeException("Not supported in system context");
311 }
312
313 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 public String getPackageResourcePath() {
315 if (mPackageInfo != null) {
316 return mPackageInfo.getResDir();
317 }
318 throw new RuntimeException("Not supported in system context");
319 }
320
321 @Override
322 public String getPackageCodePath() {
323 if (mPackageInfo != null) {
324 return mPackageInfo.getAppDir();
325 }
326 throw new RuntimeException("Not supported in system context");
327 }
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 private static File makeBackupFile(File prefsFile) {
330 return new File(prefsFile.getPath() + ".bak");
331 }
332
Joe Onorato23ecae32009-06-10 17:07:15 -0700333 public File getSharedPrefsFile(String name) {
334 return makeFilename(getPreferencesDir(), name + ".xml");
335 }
336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 @Override
338 public SharedPreferences getSharedPreferences(String name, int mode) {
339 SharedPreferencesImpl sp;
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700340 File prefsFile;
341 boolean needInitialLoad = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 synchronized (sSharedPrefs) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700343 sp = sSharedPrefs.get(name);
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700344 if (sp != null && !sp.hasFileChangedUnexpectedly()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 return sp;
346 }
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700347 prefsFile = getSharedPrefsFile(name);
348 if (sp == null) {
349 sp = new SharedPreferencesImpl(prefsFile, mode, null);
350 sSharedPrefs.put(name, sp);
351 needInitialLoad = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 }
353 }
354
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700355 synchronized (sp) {
356 if (needInitialLoad && sp.isLoaded()) {
357 // lost the race to load; another thread handled it
358 return sp;
359 }
360 File backup = makeBackupFile(prefsFile);
361 if (backup.exists()) {
362 prefsFile.delete();
363 backup.renameTo(prefsFile);
364 }
365
366 // Debugging
367 if (prefsFile.exists() && !prefsFile.canRead()) {
368 Log.w(TAG, "Attempt to read preferences file " + prefsFile + " without permission");
369 }
370
371 Map map = null;
Brad Fitzpatrickd2bbaaf2010-11-30 12:59:28 -0800372 FileStatus stat = new FileStatus();
373 if (FileUtils.getFileStatus(prefsFile.getPath(), stat) && prefsFile.canRead()) {
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700374 try {
375 FileInputStream str = new FileInputStream(prefsFile);
376 map = XmlUtils.readMapXml(str);
377 str.close();
378 } catch (org.xmlpull.v1.XmlPullParserException e) {
379 Log.w(TAG, "getSharedPreferences", e);
380 } catch (FileNotFoundException e) {
381 Log.w(TAG, "getSharedPreferences", e);
382 } catch (IOException e) {
383 Log.w(TAG, "getSharedPreferences", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 }
385 }
Brad Fitzpatrickd2bbaaf2010-11-30 12:59:28 -0800386 sp.replace(map, stat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 }
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700388 return sp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 }
390
391 private File getPreferencesDir() {
392 synchronized (mSync) {
393 if (mPreferencesDir == null) {
394 mPreferencesDir = new File(getDataDirFile(), "shared_prefs");
395 }
396 return mPreferencesDir;
397 }
398 }
399
400 @Override
401 public FileInputStream openFileInput(String name)
402 throws FileNotFoundException {
403 File f = makeFilename(getFilesDir(), name);
404 return new FileInputStream(f);
405 }
406
407 @Override
408 public FileOutputStream openFileOutput(String name, int mode)
409 throws FileNotFoundException {
410 final boolean append = (mode&MODE_APPEND) != 0;
411 File f = makeFilename(getFilesDir(), name);
412 try {
413 FileOutputStream fos = new FileOutputStream(f, append);
414 setFilePermissionsFromMode(f.getPath(), mode, 0);
415 return fos;
416 } catch (FileNotFoundException e) {
417 }
418
419 File parent = f.getParentFile();
420 parent.mkdir();
421 FileUtils.setPermissions(
422 parent.getPath(),
423 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
424 -1, -1);
425 FileOutputStream fos = new FileOutputStream(f, append);
426 setFilePermissionsFromMode(f.getPath(), mode, 0);
427 return fos;
428 }
429
430 @Override
431 public boolean deleteFile(String name) {
432 File f = makeFilename(getFilesDir(), name);
433 return f.delete();
434 }
435
436 @Override
437 public File getFilesDir() {
438 synchronized (mSync) {
439 if (mFilesDir == null) {
440 mFilesDir = new File(getDataDirFile(), "files");
441 }
442 if (!mFilesDir.exists()) {
443 if(!mFilesDir.mkdirs()) {
444 Log.w(TAG, "Unable to create files directory");
445 return null;
446 }
447 FileUtils.setPermissions(
448 mFilesDir.getPath(),
449 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
450 -1, -1);
451 }
452 return mFilesDir;
453 }
454 }
455
456 @Override
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800457 public File getExternalFilesDir(String type) {
458 synchronized (mSync) {
459 if (mExternalFilesDir == null) {
460 mExternalFilesDir = Environment.getExternalStorageAppFilesDirectory(
461 getPackageName());
462 }
463 if (!mExternalFilesDir.exists()) {
464 try {
465 (new File(Environment.getExternalStorageAndroidDataDir(),
466 ".nomedia")).createNewFile();
467 } catch (IOException e) {
468 }
469 if (!mExternalFilesDir.mkdirs()) {
470 Log.w(TAG, "Unable to create external files directory");
471 return null;
472 }
473 }
474 if (type == null) {
475 return mExternalFilesDir;
476 }
477 File dir = new File(mExternalFilesDir, type);
478 if (!dir.exists()) {
479 if (!dir.mkdirs()) {
480 Log.w(TAG, "Unable to create external media directory " + dir);
481 return null;
482 }
483 }
484 return dir;
485 }
486 }
487
488 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 public File getCacheDir() {
490 synchronized (mSync) {
491 if (mCacheDir == null) {
492 mCacheDir = new File(getDataDirFile(), "cache");
493 }
494 if (!mCacheDir.exists()) {
495 if(!mCacheDir.mkdirs()) {
496 Log.w(TAG, "Unable to create cache directory");
497 return null;
498 }
499 FileUtils.setPermissions(
500 mCacheDir.getPath(),
501 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
502 -1, -1);
503 }
504 }
505 return mCacheDir;
506 }
507
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800508 @Override
509 public File getExternalCacheDir() {
510 synchronized (mSync) {
511 if (mExternalCacheDir == null) {
512 mExternalCacheDir = Environment.getExternalStorageAppCacheDirectory(
513 getPackageName());
514 }
515 if (!mExternalCacheDir.exists()) {
516 try {
517 (new File(Environment.getExternalStorageAndroidDataDir(),
518 ".nomedia")).createNewFile();
519 } catch (IOException e) {
520 }
521 if (!mExternalCacheDir.mkdirs()) {
522 Log.w(TAG, "Unable to create external cache directory");
523 return null;
524 }
525 }
526 return mExternalCacheDir;
527 }
528 }
529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 @Override
531 public File getFileStreamPath(String name) {
532 return makeFilename(getFilesDir(), name);
533 }
534
535 @Override
536 public String[] fileList() {
537 final String[] list = getFilesDir().list();
538 return (list != null) ? list : EMPTY_FILE_LIST;
539 }
540
541 @Override
542 public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
Oscar Montemayora8529f62009-11-18 10:14:20 -0800543 File f = validateFilePath(name, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory);
545 setFilePermissionsFromMode(f.getPath(), mode, 0);
546 return db;
547 }
548
549 @Override
550 public boolean deleteDatabase(String name) {
551 try {
Oscar Montemayora8529f62009-11-18 10:14:20 -0800552 File f = validateFilePath(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 return f.delete();
554 } catch (Exception e) {
555 }
556 return false;
557 }
558
559 @Override
560 public File getDatabasePath(String name) {
Oscar Montemayora8529f62009-11-18 10:14:20 -0800561 return validateFilePath(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 }
563
564 @Override
565 public String[] databaseList() {
566 final String[] list = getDatabasesDir().list();
567 return (list != null) ? list : EMPTY_FILE_LIST;
568 }
569
570
571 private File getDatabasesDir() {
572 synchronized (mSync) {
573 if (mDatabasesDir == null) {
574 mDatabasesDir = new File(getDataDirFile(), "databases");
575 }
576 if (mDatabasesDir.getPath().equals("databases")) {
577 mDatabasesDir = new File("/data/system");
578 }
579 return mDatabasesDir;
580 }
581 }
582
583 @Override
584 public Drawable getWallpaper() {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700585 return getWallpaperManager().getDrawable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 }
587
588 @Override
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700589 public Drawable peekWallpaper() {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700590 return getWallpaperManager().peekDrawable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 }
592
593 @Override
594 public int getWallpaperDesiredMinimumWidth() {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700595 return getWallpaperManager().getDesiredMinimumWidth();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 }
597
598 @Override
599 public int getWallpaperDesiredMinimumHeight() {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700600 return getWallpaperManager().getDesiredMinimumHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 }
602
603 @Override
604 public void setWallpaper(Bitmap bitmap) throws IOException {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700605 getWallpaperManager().setBitmap(bitmap);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 }
607
608 @Override
609 public void setWallpaper(InputStream data) throws IOException {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700610 getWallpaperManager().setStream(data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 }
612
613 @Override
614 public void clearWallpaper() throws IOException {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700615 getWallpaperManager().clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 }
617
618 @Override
619 public void startActivity(Intent intent) {
620 if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
621 throw new AndroidRuntimeException(
622 "Calling startActivity() from outside of an Activity "
623 + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
624 + " Is this really what you want?");
625 }
626 mMainThread.getInstrumentation().execStartActivity(
627 getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);
628 }
629
630 @Override
Dianne Hackbornfa82f222009-09-17 15:14:12 -0700631 public void startIntentSender(IntentSender intent,
632 Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
633 throws IntentSender.SendIntentException {
634 try {
635 String resolvedType = null;
636 if (fillInIntent != null) {
637 resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
638 }
639 int result = ActivityManagerNative.getDefault()
640 .startActivityIntentSender(mMainThread.getApplicationThread(), intent,
641 fillInIntent, resolvedType, null, null,
642 0, flagsMask, flagsValues);
643 if (result == IActivityManager.START_CANCELED) {
644 throw new IntentSender.SendIntentException();
645 }
646 Instrumentation.checkStartActivityResult(result, null);
647 } catch (RemoteException e) {
648 }
649 }
650
651 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 public void sendBroadcast(Intent intent) {
653 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
654 try {
655 ActivityManagerNative.getDefault().broadcastIntent(
656 mMainThread.getApplicationThread(), intent, resolvedType, null,
657 Activity.RESULT_OK, null, null, null, false, false);
658 } catch (RemoteException e) {
659 }
660 }
661
662 @Override
663 public void sendBroadcast(Intent intent, String receiverPermission) {
664 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
665 try {
666 ActivityManagerNative.getDefault().broadcastIntent(
667 mMainThread.getApplicationThread(), intent, resolvedType, null,
668 Activity.RESULT_OK, null, null, receiverPermission, false, false);
669 } catch (RemoteException e) {
670 }
671 }
672
673 @Override
674 public void sendOrderedBroadcast(Intent intent,
675 String receiverPermission) {
676 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
677 try {
678 ActivityManagerNative.getDefault().broadcastIntent(
679 mMainThread.getApplicationThread(), intent, resolvedType, null,
680 Activity.RESULT_OK, null, null, receiverPermission, true, false);
681 } catch (RemoteException e) {
682 }
683 }
684
685 @Override
686 public void sendOrderedBroadcast(Intent intent,
687 String receiverPermission, BroadcastReceiver resultReceiver,
688 Handler scheduler, int initialCode, String initialData,
689 Bundle initialExtras) {
690 IIntentReceiver rd = null;
691 if (resultReceiver != null) {
692 if (mPackageInfo != null) {
693 if (scheduler == null) {
694 scheduler = mMainThread.getHandler();
695 }
696 rd = mPackageInfo.getReceiverDispatcher(
697 resultReceiver, getOuterContext(), scheduler,
698 mMainThread.getInstrumentation(), false);
699 } else {
700 if (scheduler == null) {
701 scheduler = mMainThread.getHandler();
702 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700703 rd = new LoadedApk.ReceiverDispatcher(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
705 }
706 }
707 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
708 try {
709 ActivityManagerNative.getDefault().broadcastIntent(
710 mMainThread.getApplicationThread(), intent, resolvedType, rd,
711 initialCode, initialData, initialExtras, receiverPermission,
712 true, false);
713 } catch (RemoteException e) {
714 }
715 }
716
717 @Override
718 public void sendStickyBroadcast(Intent intent) {
719 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
720 try {
721 ActivityManagerNative.getDefault().broadcastIntent(
722 mMainThread.getApplicationThread(), intent, resolvedType, null,
723 Activity.RESULT_OK, null, null, null, false, true);
724 } catch (RemoteException e) {
725 }
726 }
727
728 @Override
Dianne Hackbornefa199f2009-09-19 12:03:15 -0700729 public void sendStickyOrderedBroadcast(Intent intent,
730 BroadcastReceiver resultReceiver,
731 Handler scheduler, int initialCode, String initialData,
732 Bundle initialExtras) {
733 IIntentReceiver rd = null;
734 if (resultReceiver != null) {
735 if (mPackageInfo != null) {
736 if (scheduler == null) {
737 scheduler = mMainThread.getHandler();
738 }
739 rd = mPackageInfo.getReceiverDispatcher(
740 resultReceiver, getOuterContext(), scheduler,
741 mMainThread.getInstrumentation(), false);
742 } else {
743 if (scheduler == null) {
744 scheduler = mMainThread.getHandler();
745 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700746 rd = new LoadedApk.ReceiverDispatcher(
Dianne Hackbornefa199f2009-09-19 12:03:15 -0700747 resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
748 }
749 }
750 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
751 try {
752 ActivityManagerNative.getDefault().broadcastIntent(
753 mMainThread.getApplicationThread(), intent, resolvedType, rd,
754 initialCode, initialData, initialExtras, null,
755 true, true);
756 } catch (RemoteException e) {
757 }
758 }
759
760 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 public void removeStickyBroadcast(Intent intent) {
762 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
763 if (resolvedType != null) {
764 intent = new Intent(intent);
765 intent.setDataAndType(intent.getData(), resolvedType);
766 }
767 try {
768 ActivityManagerNative.getDefault().unbroadcastIntent(
769 mMainThread.getApplicationThread(), intent);
770 } catch (RemoteException e) {
771 }
772 }
773
774 @Override
775 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
776 return registerReceiver(receiver, filter, null, null);
777 }
778
779 @Override
780 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
781 String broadcastPermission, Handler scheduler) {
782 return registerReceiverInternal(receiver, filter, broadcastPermission,
783 scheduler, getOuterContext());
784 }
785
786 private Intent registerReceiverInternal(BroadcastReceiver receiver,
787 IntentFilter filter, String broadcastPermission,
788 Handler scheduler, Context context) {
789 IIntentReceiver rd = null;
790 if (receiver != null) {
791 if (mPackageInfo != null && context != null) {
792 if (scheduler == null) {
793 scheduler = mMainThread.getHandler();
794 }
795 rd = mPackageInfo.getReceiverDispatcher(
796 receiver, context, scheduler,
797 mMainThread.getInstrumentation(), true);
798 } else {
799 if (scheduler == null) {
800 scheduler = mMainThread.getHandler();
801 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700802 rd = new LoadedApk.ReceiverDispatcher(
Dianne Hackborn399cccb2010-04-13 22:57:49 -0700803 receiver, context, scheduler, null, true).getIIntentReceiver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 }
805 }
806 try {
807 return ActivityManagerNative.getDefault().registerReceiver(
808 mMainThread.getApplicationThread(),
809 rd, filter, broadcastPermission);
810 } catch (RemoteException e) {
811 return null;
812 }
813 }
814
815 @Override
816 public void unregisterReceiver(BroadcastReceiver receiver) {
817 if (mPackageInfo != null) {
818 IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
819 getOuterContext(), receiver);
820 try {
821 ActivityManagerNative.getDefault().unregisterReceiver(rd);
822 } catch (RemoteException e) {
823 }
824 } else {
825 throw new RuntimeException("Not supported in system context");
826 }
827 }
828
829 @Override
830 public ComponentName startService(Intent service) {
831 try {
832 ComponentName cn = ActivityManagerNative.getDefault().startService(
833 mMainThread.getApplicationThread(), service,
834 service.resolveTypeIfNeeded(getContentResolver()));
835 if (cn != null && cn.getPackageName().equals("!")) {
836 throw new SecurityException(
837 "Not allowed to start service " + service
838 + " without permission " + cn.getClassName());
839 }
840 return cn;
841 } catch (RemoteException e) {
842 return null;
843 }
844 }
845
846 @Override
847 public boolean stopService(Intent service) {
848 try {
849 int res = ActivityManagerNative.getDefault().stopService(
850 mMainThread.getApplicationThread(), service,
851 service.resolveTypeIfNeeded(getContentResolver()));
852 if (res < 0) {
853 throw new SecurityException(
854 "Not allowed to stop service " + service);
855 }
856 return res != 0;
857 } catch (RemoteException e) {
858 return false;
859 }
860 }
861
862 @Override
863 public boolean bindService(Intent service, ServiceConnection conn,
864 int flags) {
865 IServiceConnection sd;
866 if (mPackageInfo != null) {
867 sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
868 mMainThread.getHandler(), flags);
869 } else {
870 throw new RuntimeException("Not supported in system context");
871 }
872 try {
873 int res = ActivityManagerNative.getDefault().bindService(
874 mMainThread.getApplicationThread(), getActivityToken(),
875 service, service.resolveTypeIfNeeded(getContentResolver()),
876 sd, flags);
877 if (res < 0) {
878 throw new SecurityException(
879 "Not allowed to bind to service " + service);
880 }
881 return res != 0;
882 } catch (RemoteException e) {
883 return false;
884 }
885 }
886
887 @Override
888 public void unbindService(ServiceConnection conn) {
889 if (mPackageInfo != null) {
890 IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
891 getOuterContext(), conn);
892 try {
893 ActivityManagerNative.getDefault().unbindService(sd);
894 } catch (RemoteException e) {
895 }
896 } else {
897 throw new RuntimeException("Not supported in system context");
898 }
899 }
900
901 @Override
902 public boolean startInstrumentation(ComponentName className,
903 String profileFile, Bundle arguments) {
904 try {
905 return ActivityManagerNative.getDefault().startInstrumentation(
906 className, profileFile, 0, arguments, null);
907 } catch (RemoteException e) {
908 // System has crashed, nothing we can do.
909 }
910 return false;
911 }
912
913 @Override
914 public Object getSystemService(String name) {
915 if (WINDOW_SERVICE.equals(name)) {
916 return WindowManagerImpl.getDefault();
917 } else if (LAYOUT_INFLATER_SERVICE.equals(name)) {
918 synchronized (mSync) {
919 LayoutInflater inflater = mLayoutInflater;
920 if (inflater != null) {
921 return inflater;
922 }
923 mLayoutInflater = inflater =
924 PolicyManager.makeNewLayoutInflater(getOuterContext());
925 return inflater;
926 }
927 } else if (ACTIVITY_SERVICE.equals(name)) {
928 return getActivityManager();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700929 } else if (INPUT_METHOD_SERVICE.equals(name)) {
930 return InputMethodManager.getInstance(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 } else if (ALARM_SERVICE.equals(name)) {
932 return getAlarmManager();
Fred Quintana60307342009-03-24 22:48:12 -0700933 } else if (ACCOUNT_SERVICE.equals(name)) {
934 return getAccountManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 } else if (POWER_SERVICE.equals(name)) {
936 return getPowerManager();
937 } else if (CONNECTIVITY_SERVICE.equals(name)) {
938 return getConnectivityManager();
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700939 } else if (THROTTLE_SERVICE.equals(name)) {
940 return getThrottleManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 } else if (WIFI_SERVICE.equals(name)) {
942 return getWifiManager();
943 } else if (NOTIFICATION_SERVICE.equals(name)) {
944 return getNotificationManager();
945 } else if (KEYGUARD_SERVICE.equals(name)) {
946 return new KeyguardManager();
svetoslavganov75986cf2009-05-14 22:28:01 -0700947 } else if (ACCESSIBILITY_SERVICE.equals(name)) {
948 return AccessibilityManager.getInstance(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 } else if (LOCATION_SERVICE.equals(name)) {
950 return getLocationManager();
951 } else if (SEARCH_SERVICE.equals(name)) {
952 return getSearchManager();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700953 } else if (SENSOR_SERVICE.equals(name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 return getSensorManager();
San Mehatc9d81752010-02-01 10:23:27 -0800955 } else if (STORAGE_SERVICE.equals(name)) {
956 return getStorageManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 } else if (VIBRATOR_SERVICE.equals(name)) {
958 return getVibrator();
959 } else if (STATUS_BAR_SERVICE.equals(name)) {
960 synchronized (mSync) {
961 if (mStatusBarManager == null) {
962 mStatusBarManager = new StatusBarManager(getOuterContext());
963 }
964 return mStatusBarManager;
965 }
966 } else if (AUDIO_SERVICE.equals(name)) {
967 return getAudioManager();
968 } else if (TELEPHONY_SERVICE.equals(name)) {
969 return getTelephonyManager();
970 } else if (CLIPBOARD_SERVICE.equals(name)) {
971 return getClipboardManager();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700972 } else if (WALLPAPER_SERVICE.equals(name)) {
973 return getWallpaperManager();
Dan Egnor95240272009-10-27 18:23:39 -0700974 } else if (DROPBOX_SERVICE.equals(name)) {
Dan Egnorf18a01c2009-11-12 11:32:50 -0800975 return getDropBoxManager();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800976 } else if (DEVICE_POLICY_SERVICE.equals(name)) {
977 return getDevicePolicyManager();
Tobias Haamel69fb5742010-02-22 21:54:05 +0100978 } else if (UI_MODE_SERVICE.equals(name)) {
Tobias Haamel53332882010-02-18 16:15:43 -0800979 return getUiModeManager();
Steve Howarda2709362010-07-02 17:12:48 -0700980 } else if (DOWNLOAD_SERVICE.equals(name)) {
981 return getDownloadManager();
Nick Pelly50b4d8f2010-12-07 22:40:28 -0800982 } else if (NFC_SERVICE.equals(name)) {
983 return getNfcManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 }
985
986 return null;
987 }
988
Fred Quintana60307342009-03-24 22:48:12 -0700989 private AccountManager getAccountManager() {
Fred Quintanae00a3112009-09-22 15:13:30 -0700990 synchronized (mSync) {
991 if (mAccountManager == null) {
Fred Quintana60307342009-03-24 22:48:12 -0700992 IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
993 IAccountManager service = IAccountManager.Stub.asInterface(b);
Fred Quintanae00a3112009-09-22 15:13:30 -0700994 mAccountManager = new AccountManager(this, service);
Fred Quintana60307342009-03-24 22:48:12 -0700995 }
Fred Quintanae00a3112009-09-22 15:13:30 -0700996 return mAccountManager;
Fred Quintana60307342009-03-24 22:48:12 -0700997 }
Fred Quintana60307342009-03-24 22:48:12 -0700998 }
999
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 private ActivityManager getActivityManager() {
1001 synchronized (mSync) {
1002 if (mActivityManager == null) {
1003 mActivityManager = new ActivityManager(getOuterContext(),
1004 mMainThread.getHandler());
1005 }
1006 }
1007 return mActivityManager;
1008 }
1009
1010 private AlarmManager getAlarmManager() {
1011 synchronized (sSync) {
1012 if (sAlarmManager == null) {
1013 IBinder b = ServiceManager.getService(ALARM_SERVICE);
1014 IAlarmManager service = IAlarmManager.Stub.asInterface(b);
1015 sAlarmManager = new AlarmManager(service);
1016 }
1017 }
1018 return sAlarmManager;
1019 }
1020
1021 private PowerManager getPowerManager() {
1022 synchronized (sSync) {
1023 if (sPowerManager == null) {
1024 IBinder b = ServiceManager.getService(POWER_SERVICE);
1025 IPowerManager service = IPowerManager.Stub.asInterface(b);
1026 sPowerManager = new PowerManager(service, mMainThread.getHandler());
1027 }
1028 }
1029 return sPowerManager;
1030 }
1031
1032 private ConnectivityManager getConnectivityManager()
1033 {
1034 synchronized (sSync) {
1035 if (sConnectivityManager == null) {
1036 IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
1037 IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
1038 sConnectivityManager = new ConnectivityManager(service);
1039 }
1040 }
1041 return sConnectivityManager;
1042 }
1043
Irfan Sheriffc9b68512010-04-08 14:12:33 -07001044 private ThrottleManager getThrottleManager()
1045 {
1046 synchronized (sSync) {
1047 if (sThrottleManager == null) {
1048 IBinder b = ServiceManager.getService(THROTTLE_SERVICE);
1049 IThrottleManager service = IThrottleManager.Stub.asInterface(b);
1050 sThrottleManager = new ThrottleManager(service);
1051 }
1052 }
1053 return sThrottleManager;
1054 }
1055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 private WifiManager getWifiManager()
1057 {
1058 synchronized (sSync) {
1059 if (sWifiManager == null) {
1060 IBinder b = ServiceManager.getService(WIFI_SERVICE);
1061 IWifiManager service = IWifiManager.Stub.asInterface(b);
1062 sWifiManager = new WifiManager(service, mMainThread.getHandler());
1063 }
1064 }
1065 return sWifiManager;
1066 }
1067
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001068 private NotificationManager getNotificationManager() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 synchronized (mSync) {
1070 if (mNotificationManager == null) {
1071 mNotificationManager = new NotificationManager(
1072 new ContextThemeWrapper(getOuterContext(), com.android.internal.R.style.Theme_Dialog),
1073 mMainThread.getHandler());
1074 }
1075 }
1076 return mNotificationManager;
1077 }
1078
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001079 private WallpaperManager getWallpaperManager() {
1080 synchronized (mSync) {
1081 if (mWallpaperManager == null) {
1082 mWallpaperManager = new WallpaperManager(getOuterContext(),
1083 mMainThread.getHandler());
1084 }
1085 }
1086 return mWallpaperManager;
1087 }
1088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 private TelephonyManager getTelephonyManager() {
1090 synchronized (mSync) {
1091 if (mTelephonyManager == null) {
1092 mTelephonyManager = new TelephonyManager(getOuterContext());
1093 }
1094 }
1095 return mTelephonyManager;
1096 }
1097
1098 private ClipboardManager getClipboardManager() {
1099 synchronized (mSync) {
1100 if (mClipboardManager == null) {
1101 mClipboardManager = new ClipboardManager(getOuterContext(),
1102 mMainThread.getHandler());
1103 }
1104 }
1105 return mClipboardManager;
1106 }
1107
1108 private LocationManager getLocationManager() {
1109 synchronized (sSync) {
1110 if (sLocationManager == null) {
1111 IBinder b = ServiceManager.getService(LOCATION_SERVICE);
1112 ILocationManager service = ILocationManager.Stub.asInterface(b);
1113 sLocationManager = new LocationManager(service);
1114 }
1115 }
1116 return sLocationManager;
1117 }
1118
1119 private SearchManager getSearchManager() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 synchronized (mSync) {
1121 if (mSearchManager == null) {
1122 mSearchManager = new SearchManager(getOuterContext(), mMainThread.getHandler());
1123 }
1124 }
1125 return mSearchManager;
1126 }
1127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 private SensorManager getSensorManager() {
1129 synchronized (mSync) {
1130 if (mSensorManager == null) {
1131 mSensorManager = new SensorManager(mMainThread.getHandler().getLooper());
1132 }
1133 }
1134 return mSensorManager;
1135 }
1136
San Mehatc9d81752010-02-01 10:23:27 -08001137 private StorageManager getStorageManager() {
1138 synchronized (mSync) {
1139 if (mStorageManager == null) {
1140 try {
1141 mStorageManager = new StorageManager(mMainThread.getHandler().getLooper());
1142 } catch (RemoteException rex) {
1143 Log.e(TAG, "Failed to create StorageManager", rex);
1144 mStorageManager = null;
1145 }
1146 }
1147 }
1148 return mStorageManager;
1149 }
1150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 private Vibrator getVibrator() {
1152 synchronized (mSync) {
1153 if (mVibrator == null) {
1154 mVibrator = new Vibrator();
1155 }
1156 }
1157 return mVibrator;
1158 }
Dan Egnor95240272009-10-27 18:23:39 -07001159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 private AudioManager getAudioManager()
1161 {
1162 if (mAudioManager == null) {
1163 mAudioManager = new AudioManager(this);
1164 }
1165 return mAudioManager;
1166 }
1167
Brad Fitzpatrick438d0592010-06-10 12:19:19 -07001168 /* package */ static DropBoxManager createDropBoxManager() {
1169 IBinder b = ServiceManager.getService(DROPBOX_SERVICE);
1170 IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
1171 return new DropBoxManager(service);
1172 }
1173
Dan Egnorf18a01c2009-11-12 11:32:50 -08001174 private DropBoxManager getDropBoxManager() {
Dan Egnor95240272009-10-27 18:23:39 -07001175 synchronized (mSync) {
Dan Egnorf18a01c2009-11-12 11:32:50 -08001176 if (mDropBoxManager == null) {
Brad Fitzpatrick438d0592010-06-10 12:19:19 -07001177 mDropBoxManager = createDropBoxManager();
Dan Egnor95240272009-10-27 18:23:39 -07001178 }
1179 }
Dan Egnorf18a01c2009-11-12 11:32:50 -08001180 return mDropBoxManager;
Dan Egnor95240272009-10-27 18:23:39 -07001181 }
1182
Dianne Hackbornd6847842010-01-12 18:14:19 -08001183 private DevicePolicyManager getDevicePolicyManager() {
1184 synchronized (mSync) {
1185 if (mDevicePolicyManager == null) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001186 mDevicePolicyManager = DevicePolicyManager.create(this,
Dianne Hackbornd6847842010-01-12 18:14:19 -08001187 mMainThread.getHandler());
1188 }
1189 }
1190 return mDevicePolicyManager;
1191 }
1192
Tobias Haamel53332882010-02-18 16:15:43 -08001193 private UiModeManager getUiModeManager() {
1194 synchronized (mSync) {
1195 if (mUiModeManager == null) {
1196 mUiModeManager = new UiModeManager();
1197 }
1198 }
1199 return mUiModeManager;
1200 }
1201
Steve Howarda2709362010-07-02 17:12:48 -07001202 private DownloadManager getDownloadManager() {
1203 synchronized (mSync) {
1204 if (mDownloadManager == null) {
Steve Howardb8e07a52010-07-21 14:53:21 -07001205 mDownloadManager = new DownloadManager(getContentResolver(), getPackageName());
Steve Howarda2709362010-07-02 17:12:48 -07001206 }
1207 }
1208 return mDownloadManager;
1209 }
1210
Nick Pelly50b4d8f2010-12-07 22:40:28 -08001211 private NfcManager getNfcManager() {
1212 synchronized (mSync) {
1213 if (mNfcManager == null) {
1214 mNfcManager = new NfcManager(this);
1215 }
1216 }
1217 return mNfcManager;
1218 }
1219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 @Override
1221 public int checkPermission(String permission, int pid, int uid) {
1222 if (permission == null) {
1223 throw new IllegalArgumentException("permission is null");
1224 }
1225
1226 if (!Process.supportsProcesses()) {
1227 return PackageManager.PERMISSION_GRANTED;
1228 }
1229 try {
1230 return ActivityManagerNative.getDefault().checkPermission(
1231 permission, pid, uid);
1232 } catch (RemoteException e) {
1233 return PackageManager.PERMISSION_DENIED;
1234 }
1235 }
1236
1237 @Override
1238 public int checkCallingPermission(String permission) {
1239 if (permission == null) {
1240 throw new IllegalArgumentException("permission is null");
1241 }
1242
1243 if (!Process.supportsProcesses()) {
1244 return PackageManager.PERMISSION_GRANTED;
1245 }
1246 int pid = Binder.getCallingPid();
1247 if (pid != Process.myPid()) {
1248 return checkPermission(permission, pid,
1249 Binder.getCallingUid());
1250 }
1251 return PackageManager.PERMISSION_DENIED;
1252 }
1253
1254 @Override
1255 public int checkCallingOrSelfPermission(String permission) {
1256 if (permission == null) {
1257 throw new IllegalArgumentException("permission is null");
1258 }
1259
1260 return checkPermission(permission, Binder.getCallingPid(),
1261 Binder.getCallingUid());
1262 }
1263
1264 private void enforce(
1265 String permission, int resultOfCheck,
1266 boolean selfToo, int uid, String message) {
1267 if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
1268 throw new SecurityException(
1269 (message != null ? (message + ": ") : "") +
1270 (selfToo
1271 ? "Neither user " + uid + " nor current process has "
1272 : "User " + uid + " does not have ") +
1273 permission +
1274 ".");
1275 }
1276 }
1277
1278 public void enforcePermission(
1279 String permission, int pid, int uid, String message) {
1280 enforce(permission,
1281 checkPermission(permission, pid, uid),
1282 false,
1283 uid,
1284 message);
1285 }
1286
1287 public void enforceCallingPermission(String permission, String message) {
1288 enforce(permission,
1289 checkCallingPermission(permission),
1290 false,
1291 Binder.getCallingUid(),
1292 message);
1293 }
1294
1295 public void enforceCallingOrSelfPermission(
1296 String permission, String message) {
1297 enforce(permission,
1298 checkCallingOrSelfPermission(permission),
1299 true,
1300 Binder.getCallingUid(),
1301 message);
1302 }
1303
1304 @Override
1305 public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
1306 try {
1307 ActivityManagerNative.getDefault().grantUriPermission(
1308 mMainThread.getApplicationThread(), toPackage, uri,
1309 modeFlags);
1310 } catch (RemoteException e) {
1311 }
1312 }
1313
1314 @Override
1315 public void revokeUriPermission(Uri uri, int modeFlags) {
1316 try {
1317 ActivityManagerNative.getDefault().revokeUriPermission(
1318 mMainThread.getApplicationThread(), uri,
1319 modeFlags);
1320 } catch (RemoteException e) {
1321 }
1322 }
1323
1324 @Override
1325 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
1326 if (!Process.supportsProcesses()) {
1327 return PackageManager.PERMISSION_GRANTED;
1328 }
1329 try {
1330 return ActivityManagerNative.getDefault().checkUriPermission(
1331 uri, pid, uid, modeFlags);
1332 } catch (RemoteException e) {
1333 return PackageManager.PERMISSION_DENIED;
1334 }
1335 }
1336
1337 @Override
1338 public int checkCallingUriPermission(Uri uri, int modeFlags) {
1339 if (!Process.supportsProcesses()) {
1340 return PackageManager.PERMISSION_GRANTED;
1341 }
1342 int pid = Binder.getCallingPid();
1343 if (pid != Process.myPid()) {
1344 return checkUriPermission(uri, pid,
1345 Binder.getCallingUid(), modeFlags);
1346 }
1347 return PackageManager.PERMISSION_DENIED;
1348 }
1349
1350 @Override
1351 public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) {
1352 return checkUriPermission(uri, Binder.getCallingPid(),
1353 Binder.getCallingUid(), modeFlags);
1354 }
1355
1356 @Override
1357 public int checkUriPermission(Uri uri, String readPermission,
1358 String writePermission, int pid, int uid, int modeFlags) {
Mitsuru Oshima569076c2009-07-02 20:06:08 -07001359 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 Log.i("foo", "checkUriPermission: uri=" + uri + "readPermission="
1361 + readPermission + " writePermission=" + writePermission
1362 + " pid=" + pid + " uid=" + uid + " mode" + modeFlags);
1363 }
1364 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
1365 if (readPermission == null
1366 || checkPermission(readPermission, pid, uid)
1367 == PackageManager.PERMISSION_GRANTED) {
1368 return PackageManager.PERMISSION_GRANTED;
1369 }
1370 }
1371 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
1372 if (writePermission == null
1373 || checkPermission(writePermission, pid, uid)
1374 == PackageManager.PERMISSION_GRANTED) {
1375 return PackageManager.PERMISSION_GRANTED;
1376 }
1377 }
1378 return uri != null ? checkUriPermission(uri, pid, uid, modeFlags)
1379 : PackageManager.PERMISSION_DENIED;
1380 }
1381
1382 private String uriModeFlagToString(int uriModeFlags) {
1383 switch (uriModeFlags) {
1384 case Intent.FLAG_GRANT_READ_URI_PERMISSION |
1385 Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
1386 return "read and write";
1387 case Intent.FLAG_GRANT_READ_URI_PERMISSION:
1388 return "read";
1389 case Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
1390 return "write";
1391 }
1392 throw new IllegalArgumentException(
1393 "Unknown permission mode flags: " + uriModeFlags);
1394 }
1395
1396 private void enforceForUri(
1397 int modeFlags, int resultOfCheck, boolean selfToo,
1398 int uid, Uri uri, String message) {
1399 if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
1400 throw new SecurityException(
1401 (message != null ? (message + ": ") : "") +
1402 (selfToo
1403 ? "Neither user " + uid + " nor current process has "
1404 : "User " + uid + " does not have ") +
1405 uriModeFlagToString(modeFlags) +
1406 " permission on " +
1407 uri +
1408 ".");
1409 }
1410 }
1411
1412 public void enforceUriPermission(
1413 Uri uri, int pid, int uid, int modeFlags, String message) {
1414 enforceForUri(
1415 modeFlags, checkUriPermission(uri, pid, uid, modeFlags),
1416 false, uid, uri, message);
1417 }
1418
1419 public void enforceCallingUriPermission(
1420 Uri uri, int modeFlags, String message) {
1421 enforceForUri(
1422 modeFlags, checkCallingUriPermission(uri, modeFlags),
1423 false, Binder.getCallingUid(), uri, message);
1424 }
1425
1426 public void enforceCallingOrSelfUriPermission(
1427 Uri uri, int modeFlags, String message) {
1428 enforceForUri(
1429 modeFlags,
1430 checkCallingOrSelfUriPermission(uri, modeFlags), true,
1431 Binder.getCallingUid(), uri, message);
1432 }
1433
1434 public void enforceUriPermission(
1435 Uri uri, String readPermission, String writePermission,
1436 int pid, int uid, int modeFlags, String message) {
1437 enforceForUri(modeFlags,
1438 checkUriPermission(
1439 uri, readPermission, writePermission, pid, uid,
1440 modeFlags),
1441 false,
1442 uid,
1443 uri,
1444 message);
1445 }
1446
1447 @Override
1448 public Context createPackageContext(String packageName, int flags)
1449 throws PackageManager.NameNotFoundException {
1450 if (packageName.equals("system") || packageName.equals("android")) {
Dianne Hackborn21556372010-02-04 16:34:40 -08001451 return new ContextImpl(mMainThread.getSystemContext());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 }
1453
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001454 LoadedApk pi =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 mMainThread.getPackageInfo(packageName, flags);
1456 if (pi != null) {
Dianne Hackborn21556372010-02-04 16:34:40 -08001457 ContextImpl c = new ContextImpl();
Romain Guy870e09f2009-07-06 16:35:25 -07001458 c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001459 c.init(pi, null, mMainThread, mResources);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 if (c.mResources != null) {
1461 return c;
1462 }
1463 }
1464
1465 // Should be a better exception.
1466 throw new PackageManager.NameNotFoundException(
1467 "Application package " + packageName + " not found");
1468 }
1469
Romain Guy870e09f2009-07-06 16:35:25 -07001470 @Override
1471 public boolean isRestricted() {
1472 return mRestricted;
1473 }
1474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001475 private File getDataDirFile() {
1476 if (mPackageInfo != null) {
1477 return mPackageInfo.getDataDirFile();
1478 }
1479 throw new RuntimeException("Not supported in system context");
1480 }
1481
1482 @Override
1483 public File getDir(String name, int mode) {
1484 name = "app_" + name;
1485 File file = makeFilename(getDataDirFile(), name);
1486 if (!file.exists()) {
1487 file.mkdir();
1488 setFilePermissionsFromMode(file.getPath(), mode,
1489 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH);
1490 }
1491 return file;
1492 }
1493
Dianne Hackborn21556372010-02-04 16:34:40 -08001494 static ContextImpl createSystemContext(ActivityThread mainThread) {
1495 ContextImpl context = new ContextImpl();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 context.init(Resources.getSystem(), mainThread);
1497 return context;
1498 }
1499
Dianne Hackborn21556372010-02-04 16:34:40 -08001500 ContextImpl() {
Carl Shapiro82fe5642010-02-24 00:14:23 -08001501 // For debug only
1502 //++sInstanceCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001503 mOuterContext = this;
1504 }
1505
1506 /**
1507 * Create a new ApplicationContext from an existing one. The new one
1508 * works and operates the same as the one it is copying.
1509 *
1510 * @param context Existing application context.
1511 */
Dianne Hackborn21556372010-02-04 16:34:40 -08001512 public ContextImpl(ContextImpl context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 ++sInstanceCount;
1514 mPackageInfo = context.mPackageInfo;
1515 mResources = context.mResources;
1516 mMainThread = context.mMainThread;
1517 mContentResolver = context.mContentResolver;
1518 mOuterContext = this;
1519 }
1520
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001521 final void init(LoadedApk packageInfo,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 IBinder activityToken, ActivityThread mainThread) {
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001523 init(packageInfo, activityToken, mainThread, null);
1524 }
1525
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001526 final void init(LoadedApk packageInfo,
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001527 IBinder activityToken, ActivityThread mainThread,
1528 Resources container) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001529 mPackageInfo = packageInfo;
1530 mResources = mPackageInfo.getResources(mainThread);
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001531
Dianne Hackborn559a7872010-04-07 18:19:41 -07001532 if (mResources != null && container != null
1533 && container.getCompatibilityInfo().applicationScale !=
1534 mResources.getCompatibilityInfo().applicationScale) {
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001535 if (DEBUG) {
1536 Log.d(TAG, "loaded context has different scaling. Using container's" +
1537 " compatiblity info:" + container.getDisplayMetrics());
1538 }
1539 mResources = mainThread.getTopLevelResources(
1540 mPackageInfo.getResDir(), container.getCompatibilityInfo().copy());
1541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 mMainThread = mainThread;
1543 mContentResolver = new ApplicationContentResolver(this, mainThread);
1544
1545 setActivityToken(activityToken);
1546 }
1547
1548 final void init(Resources resources, ActivityThread mainThread) {
1549 mPackageInfo = null;
1550 mResources = resources;
1551 mMainThread = mainThread;
1552 mContentResolver = new ApplicationContentResolver(this, mainThread);
1553 }
1554
1555 final void scheduleFinalCleanup(String who, String what) {
1556 mMainThread.scheduleContextCleanup(this, who, what);
1557 }
1558
1559 final void performFinalCleanup(String who, String what) {
1560 //Log.i(TAG, "Cleanup up context: " + this);
1561 mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
1562 }
1563
1564 final Context getReceiverRestrictedContext() {
1565 if (mReceiverRestrictedContext != null) {
1566 return mReceiverRestrictedContext;
1567 }
1568 return mReceiverRestrictedContext = new ReceiverRestrictedContext(getOuterContext());
1569 }
1570
1571 final void setActivityToken(IBinder token) {
1572 mActivityToken = token;
1573 }
1574
1575 final void setOuterContext(Context context) {
1576 mOuterContext = context;
1577 }
1578
1579 final Context getOuterContext() {
1580 return mOuterContext;
1581 }
1582
1583 final IBinder getActivityToken() {
1584 return mActivityToken;
1585 }
1586
1587 private static void setFilePermissionsFromMode(String name, int mode,
1588 int extraPermissions) {
1589 int perms = FileUtils.S_IRUSR|FileUtils.S_IWUSR
1590 |FileUtils.S_IRGRP|FileUtils.S_IWGRP
1591 |extraPermissions;
1592 if ((mode&MODE_WORLD_READABLE) != 0) {
1593 perms |= FileUtils.S_IROTH;
1594 }
1595 if ((mode&MODE_WORLD_WRITEABLE) != 0) {
1596 perms |= FileUtils.S_IWOTH;
1597 }
Mitsuru Oshima569076c2009-07-02 20:06:08 -07001598 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 Log.i(TAG, "File " + name + ": mode=0x" + Integer.toHexString(mode)
1600 + ", perms=0x" + Integer.toHexString(perms));
1601 }
1602 FileUtils.setPermissions(name, perms, -1, -1);
1603 }
1604
Oscar Montemayora8529f62009-11-18 10:14:20 -08001605 private File validateFilePath(String name, boolean createDirectory) {
1606 File dir;
1607 File f;
1608
1609 if (name.charAt(0) == File.separatorChar) {
1610 String dirPath = name.substring(0, name.lastIndexOf(File.separatorChar));
1611 dir = new File(dirPath);
1612 name = name.substring(name.lastIndexOf(File.separatorChar));
1613 f = new File(dir, name);
1614 } else {
1615 dir = getDatabasesDir();
1616 f = makeFilename(dir, name);
1617 }
1618
1619 if (createDirectory && !dir.isDirectory() && dir.mkdir()) {
1620 FileUtils.setPermissions(dir.getPath(),
1621 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
1622 -1, -1);
1623 }
1624
1625 return f;
1626 }
1627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 private File makeFilename(File base, String name) {
1629 if (name.indexOf(File.separatorChar) < 0) {
1630 return new File(base, name);
1631 }
1632 throw new IllegalArgumentException(
Oscar Montemayora8529f62009-11-18 10:14:20 -08001633 "File " + name + " contains a path separator");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 }
1635
1636 // ----------------------------------------------------------------------
1637 // ----------------------------------------------------------------------
1638 // ----------------------------------------------------------------------
1639
1640 private static final class ApplicationContentResolver extends ContentResolver {
Dianne Hackborn8313fc72010-09-26 18:34:53 -07001641 public ApplicationContentResolver(Context context, ActivityThread mainThread) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 super(context);
1643 mMainThread = mainThread;
1644 }
1645
1646 @Override
Dianne Hackborn8313fc72010-09-26 18:34:53 -07001647 protected IContentProvider acquireProvider(Context context, String name) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648 return mMainThread.acquireProvider(context, name);
1649 }
1650
1651 @Override
Dianne Hackborn8313fc72010-09-26 18:34:53 -07001652 protected IContentProvider acquireExistingProvider(Context context, String name) {
1653 return mMainThread.acquireExistingProvider(context, name);
1654 }
1655
1656 @Override
1657 public boolean releaseProvider(IContentProvider provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 return mMainThread.releaseProvider(provider);
1659 }
1660
1661 private final ActivityThread mMainThread;
1662 }
1663
1664 // ----------------------------------------------------------------------
1665 // ----------------------------------------------------------------------
1666 // ----------------------------------------------------------------------
1667
1668 /*package*/
1669 static final class ApplicationPackageManager extends PackageManager {
1670 @Override
1671 public PackageInfo getPackageInfo(String packageName, int flags)
1672 throws NameNotFoundException {
1673 try {
1674 PackageInfo pi = mPM.getPackageInfo(packageName, flags);
1675 if (pi != null) {
1676 return pi;
1677 }
1678 } catch (RemoteException e) {
1679 throw new RuntimeException("Package manager has died", e);
1680 }
1681
1682 throw new NameNotFoundException(packageName);
1683 }
1684
Mihai Predaeae850c2009-05-13 10:13:48 +02001685 @Override
Dianne Hackborn47096932010-02-11 15:57:09 -08001686 public String[] currentToCanonicalPackageNames(String[] names) {
1687 try {
1688 return mPM.currentToCanonicalPackageNames(names);
1689 } catch (RemoteException e) {
1690 throw new RuntimeException("Package manager has died", e);
1691 }
1692 }
1693
1694 @Override
1695 public String[] canonicalToCurrentPackageNames(String[] names) {
1696 try {
1697 return mPM.canonicalToCurrentPackageNames(names);
1698 } catch (RemoteException e) {
1699 throw new RuntimeException("Package manager has died", e);
1700 }
1701 }
1702
1703 @Override
Mihai Predaeae850c2009-05-13 10:13:48 +02001704 public Intent getLaunchIntentForPackage(String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 // First see if the package has an INFO activity; the existence of
1706 // such an activity is implied to be the desired front-door for the
1707 // overall package (such as if it has multiple launcher entries).
Mihai Predaeae850c2009-05-13 10:13:48 +02001708 Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1709 intentToResolve.addCategory(Intent.CATEGORY_INFO);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07001710 intentToResolve.setPackage(packageName);
1711 ResolveInfo resolveInfo = resolveActivity(intentToResolve, 0);
Mihai Predaeae850c2009-05-13 10:13:48 +02001712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 // Otherwise, try to find a main launcher activity.
Mihai Predaeae850c2009-05-13 10:13:48 +02001714 if (resolveInfo == null) {
1715 // reuse the intent instance
1716 intentToResolve.removeCategory(Intent.CATEGORY_INFO);
1717 intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07001718 intentToResolve.setPackage(packageName);
1719 resolveInfo = resolveActivity(intentToResolve, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 }
Mihai Predaeae850c2009-05-13 10:13:48 +02001721 if (resolveInfo == null) {
1722 return null;
1723 }
1724 Intent intent = new Intent(Intent.ACTION_MAIN);
1725 intent.setClassName(packageName, resolveInfo.activityInfo.name);
1726 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1727 return intent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 }
Mihai Predaeae850c2009-05-13 10:13:48 +02001729
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 @Override
1731 public int[] getPackageGids(String packageName)
1732 throws NameNotFoundException {
1733 try {
1734 int[] gids = mPM.getPackageGids(packageName);
1735 if (gids == null || gids.length > 0) {
1736 return gids;
1737 }
1738 } catch (RemoteException e) {
1739 throw new RuntimeException("Package manager has died", e);
1740 }
1741
1742 throw new NameNotFoundException(packageName);
1743 }
1744
1745 @Override
1746 public PermissionInfo getPermissionInfo(String name, int flags)
1747 throws NameNotFoundException {
1748 try {
1749 PermissionInfo pi = mPM.getPermissionInfo(name, flags);
1750 if (pi != null) {
1751 return pi;
1752 }
1753 } catch (RemoteException e) {
1754 throw new RuntimeException("Package manager has died", e);
1755 }
1756
1757 throw new NameNotFoundException(name);
1758 }
1759
1760 @Override
1761 public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
1762 throws NameNotFoundException {
1763 try {
1764 List<PermissionInfo> pi = mPM.queryPermissionsByGroup(group, flags);
1765 if (pi != null) {
1766 return pi;
1767 }
1768 } catch (RemoteException e) {
1769 throw new RuntimeException("Package manager has died", e);
1770 }
1771
1772 throw new NameNotFoundException(group);
1773 }
1774
1775 @Override
1776 public PermissionGroupInfo getPermissionGroupInfo(String name,
1777 int flags) throws NameNotFoundException {
1778 try {
1779 PermissionGroupInfo pgi = mPM.getPermissionGroupInfo(name, flags);
1780 if (pgi != null) {
1781 return pgi;
1782 }
1783 } catch (RemoteException e) {
1784 throw new RuntimeException("Package manager has died", e);
1785 }
1786
1787 throw new NameNotFoundException(name);
1788 }
1789
1790 @Override
1791 public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
1792 try {
1793 return mPM.getAllPermissionGroups(flags);
1794 } catch (RemoteException e) {
1795 throw new RuntimeException("Package manager has died", e);
1796 }
1797 }
1798
1799 @Override
1800 public ApplicationInfo getApplicationInfo(String packageName, int flags)
1801 throws NameNotFoundException {
1802 try {
1803 ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags);
1804 if (ai != null) {
1805 return ai;
1806 }
1807 } catch (RemoteException e) {
1808 throw new RuntimeException("Package manager has died", e);
1809 }
1810
1811 throw new NameNotFoundException(packageName);
1812 }
1813
1814 @Override
1815 public ActivityInfo getActivityInfo(ComponentName className, int flags)
1816 throws NameNotFoundException {
1817 try {
1818 ActivityInfo ai = mPM.getActivityInfo(className, flags);
1819 if (ai != null) {
1820 return ai;
1821 }
1822 } catch (RemoteException e) {
1823 throw new RuntimeException("Package manager has died", e);
1824 }
1825
1826 throw new NameNotFoundException(className.toString());
1827 }
1828
1829 @Override
1830 public ActivityInfo getReceiverInfo(ComponentName className, int flags)
1831 throws NameNotFoundException {
1832 try {
1833 ActivityInfo ai = mPM.getReceiverInfo(className, flags);
1834 if (ai != null) {
1835 return ai;
1836 }
1837 } catch (RemoteException e) {
1838 throw new RuntimeException("Package manager has died", e);
1839 }
1840
1841 throw new NameNotFoundException(className.toString());
1842 }
1843
1844 @Override
1845 public ServiceInfo getServiceInfo(ComponentName className, int flags)
1846 throws NameNotFoundException {
1847 try {
1848 ServiceInfo si = mPM.getServiceInfo(className, flags);
1849 if (si != null) {
1850 return si;
1851 }
1852 } catch (RemoteException e) {
1853 throw new RuntimeException("Package manager has died", e);
1854 }
1855
1856 throw new NameNotFoundException(className.toString());
1857 }
1858
1859 @Override
Dianne Hackborn361199b2010-08-30 17:42:07 -07001860 public ProviderInfo getProviderInfo(ComponentName className, int flags)
1861 throws NameNotFoundException {
1862 try {
1863 ProviderInfo pi = mPM.getProviderInfo(className, flags);
1864 if (pi != null) {
1865 return pi;
1866 }
1867 } catch (RemoteException e) {
1868 throw new RuntimeException("Package manager has died", e);
1869 }
1870
1871 throw new NameNotFoundException(className.toString());
1872 }
1873
1874 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 public String[] getSystemSharedLibraryNames() {
1876 try {
1877 return mPM.getSystemSharedLibraryNames();
1878 } catch (RemoteException e) {
1879 throw new RuntimeException("Package manager has died", e);
1880 }
1881 }
1882
1883 @Override
Dianne Hackborn49237342009-08-27 20:08:01 -07001884 public FeatureInfo[] getSystemAvailableFeatures() {
1885 try {
1886 return mPM.getSystemAvailableFeatures();
1887 } catch (RemoteException e) {
1888 throw new RuntimeException("Package manager has died", e);
1889 }
1890 }
1891
1892 @Override
Dianne Hackborn039c68e2009-09-26 16:39:23 -07001893 public boolean hasSystemFeature(String name) {
1894 try {
1895 return mPM.hasSystemFeature(name);
1896 } catch (RemoteException e) {
1897 throw new RuntimeException("Package manager has died", e);
1898 }
1899 }
1900
1901 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 public int checkPermission(String permName, String pkgName) {
1903 try {
1904 return mPM.checkPermission(permName, pkgName);
1905 } catch (RemoteException e) {
1906 throw new RuntimeException("Package manager has died", e);
1907 }
1908 }
1909
1910 @Override
1911 public boolean addPermission(PermissionInfo info) {
1912 try {
1913 return mPM.addPermission(info);
1914 } catch (RemoteException e) {
1915 throw new RuntimeException("Package manager has died", e);
1916 }
1917 }
1918
1919 @Override
Dianne Hackbornd7c09682010-03-30 10:42:20 -07001920 public boolean addPermissionAsync(PermissionInfo info) {
1921 try {
1922 return mPM.addPermissionAsync(info);
1923 } catch (RemoteException e) {
1924 throw new RuntimeException("Package manager has died", e);
1925 }
1926 }
1927
1928 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 public void removePermission(String name) {
1930 try {
1931 mPM.removePermission(name);
1932 } catch (RemoteException e) {
1933 throw new RuntimeException("Package manager has died", e);
1934 }
1935 }
1936
1937 @Override
1938 public int checkSignatures(String pkg1, String pkg2) {
1939 try {
1940 return mPM.checkSignatures(pkg1, pkg2);
1941 } catch (RemoteException e) {
1942 throw new RuntimeException("Package manager has died", e);
1943 }
1944 }
1945
1946 @Override
Dianne Hackborn766cbfe2009-08-12 18:33:39 -07001947 public int checkSignatures(int uid1, int uid2) {
1948 try {
1949 return mPM.checkUidSignatures(uid1, uid2);
1950 } catch (RemoteException e) {
1951 throw new RuntimeException("Package manager has died", e);
1952 }
1953 }
1954
1955 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 public String[] getPackagesForUid(int uid) {
1957 try {
1958 return mPM.getPackagesForUid(uid);
1959 } catch (RemoteException e) {
1960 throw new RuntimeException("Package manager has died", e);
1961 }
1962 }
1963
1964 @Override
1965 public String getNameForUid(int uid) {
1966 try {
1967 return mPM.getNameForUid(uid);
1968 } catch (RemoteException e) {
1969 throw new RuntimeException("Package manager has died", e);
1970 }
1971 }
1972
1973 @Override
1974 public int getUidForSharedUser(String sharedUserName)
1975 throws NameNotFoundException {
1976 try {
1977 int uid = mPM.getUidForSharedUser(sharedUserName);
1978 if(uid != -1) {
1979 return uid;
1980 }
1981 } catch (RemoteException e) {
1982 throw new RuntimeException("Package manager has died", e);
1983 }
1984 throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
1985 }
1986
1987 @Override
1988 public List<PackageInfo> getInstalledPackages(int flags) {
1989 try {
1990 return mPM.getInstalledPackages(flags);
1991 } catch (RemoteException e) {
1992 throw new RuntimeException("Package manager has died", e);
1993 }
1994 }
1995
1996 @Override
1997 public List<ApplicationInfo> getInstalledApplications(int flags) {
1998 try {
1999 return mPM.getInstalledApplications(flags);
2000 } catch (RemoteException e) {
2001 throw new RuntimeException("Package manager has died", e);
2002 }
2003 }
2004
2005 @Override
2006 public ResolveInfo resolveActivity(Intent intent, int flags) {
2007 try {
2008 return mPM.resolveIntent(
2009 intent,
2010 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2011 flags);
2012 } catch (RemoteException e) {
2013 throw new RuntimeException("Package manager has died", e);
2014 }
2015 }
2016
2017 @Override
2018 public List<ResolveInfo> queryIntentActivities(Intent intent,
2019 int flags) {
2020 try {
2021 return mPM.queryIntentActivities(
2022 intent,
2023 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2024 flags);
2025 } catch (RemoteException e) {
2026 throw new RuntimeException("Package manager has died", e);
2027 }
2028 }
2029
2030 @Override
2031 public List<ResolveInfo> queryIntentActivityOptions(
2032 ComponentName caller, Intent[] specifics, Intent intent,
2033 int flags) {
2034 final ContentResolver resolver = mContext.getContentResolver();
2035
2036 String[] specificTypes = null;
2037 if (specifics != null) {
2038 final int N = specifics.length;
2039 for (int i=0; i<N; i++) {
2040 Intent sp = specifics[i];
2041 if (sp != null) {
2042 String t = sp.resolveTypeIfNeeded(resolver);
2043 if (t != null) {
2044 if (specificTypes == null) {
2045 specificTypes = new String[N];
2046 }
2047 specificTypes[i] = t;
2048 }
2049 }
2050 }
2051 }
2052
2053 try {
2054 return mPM.queryIntentActivityOptions(caller, specifics,
2055 specificTypes, intent, intent.resolveTypeIfNeeded(resolver),
2056 flags);
2057 } catch (RemoteException e) {
2058 throw new RuntimeException("Package manager has died", e);
2059 }
2060 }
2061
2062 @Override
2063 public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
2064 try {
2065 return mPM.queryIntentReceivers(
2066 intent,
2067 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2068 flags);
2069 } catch (RemoteException e) {
2070 throw new RuntimeException("Package manager has died", e);
2071 }
2072 }
2073
2074 @Override
2075 public ResolveInfo resolveService(Intent intent, int flags) {
2076 try {
2077 return mPM.resolveService(
2078 intent,
2079 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2080 flags);
2081 } catch (RemoteException e) {
2082 throw new RuntimeException("Package manager has died", e);
2083 }
2084 }
2085
2086 @Override
2087 public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
2088 try {
2089 return mPM.queryIntentServices(
2090 intent,
2091 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2092 flags);
2093 } catch (RemoteException e) {
2094 throw new RuntimeException("Package manager has died", e);
2095 }
2096 }
2097
2098 @Override
2099 public ProviderInfo resolveContentProvider(String name,
2100 int flags) {
2101 try {
2102 return mPM.resolveContentProvider(name, flags);
2103 } catch (RemoteException e) {
2104 throw new RuntimeException("Package manager has died", e);
2105 }
2106 }
2107
2108 @Override
2109 public List<ProviderInfo> queryContentProviders(String processName,
2110 int uid, int flags) {
2111 try {
2112 return mPM.queryContentProviders(processName, uid, flags);
2113 } catch (RemoteException e) {
2114 throw new RuntimeException("Package manager has died", e);
2115 }
2116 }
2117
2118 @Override
2119 public InstrumentationInfo getInstrumentationInfo(
2120 ComponentName className, int flags)
2121 throws NameNotFoundException {
2122 try {
2123 InstrumentationInfo ii = mPM.getInstrumentationInfo(
2124 className, flags);
2125 if (ii != null) {
2126 return ii;
2127 }
2128 } catch (RemoteException e) {
2129 throw new RuntimeException("Package manager has died", e);
2130 }
2131
2132 throw new NameNotFoundException(className.toString());
2133 }
2134
2135 @Override
2136 public List<InstrumentationInfo> queryInstrumentation(
2137 String targetPackage, int flags) {
2138 try {
2139 return mPM.queryInstrumentation(targetPackage, flags);
2140 } catch (RemoteException e) {
2141 throw new RuntimeException("Package manager has died", e);
2142 }
2143 }
2144
2145 @Override public Drawable getDrawable(String packageName, int resid,
2146 ApplicationInfo appInfo) {
2147 ResourceName name = new ResourceName(packageName, resid);
2148 Drawable dr = getCachedIcon(name);
2149 if (dr != null) {
2150 return dr;
2151 }
2152 if (appInfo == null) {
2153 try {
2154 appInfo = getApplicationInfo(packageName, 0);
2155 } catch (NameNotFoundException e) {
2156 return null;
2157 }
2158 }
2159 try {
2160 Resources r = getResourcesForApplication(appInfo);
2161 dr = r.getDrawable(resid);
Dianne Hackborn11ea3342009-07-22 21:48:55 -07002162 if (false) {
2163 RuntimeException e = new RuntimeException("here");
2164 e.fillInStackTrace();
2165 Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resid)
2166 + " from package " + packageName
2167 + ": app scale=" + r.getCompatibilityInfo().applicationScale
2168 + ", caller scale=" + mContext.getResources().getCompatibilityInfo().applicationScale,
2169 e);
2170 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x"
2172 + Integer.toHexString(resid) + " from " + r
2173 + ": " + dr);
2174 putCachedIcon(name, dr);
2175 return dr;
2176 } catch (NameNotFoundException e) {
2177 Log.w("PackageManager", "Failure retrieving resources for"
2178 + appInfo.packageName);
2179 } catch (RuntimeException e) {
2180 // If an exception was thrown, fall through to return
2181 // default icon.
2182 Log.w("PackageManager", "Failure retrieving icon 0x"
2183 + Integer.toHexString(resid) + " in package "
2184 + packageName, e);
2185 }
2186 return null;
2187 }
2188
2189 @Override public Drawable getActivityIcon(ComponentName activityName)
2190 throws NameNotFoundException {
2191 return getActivityInfo(activityName, 0).loadIcon(this);
2192 }
2193
2194 @Override public Drawable getActivityIcon(Intent intent)
2195 throws NameNotFoundException {
2196 if (intent.getComponent() != null) {
2197 return getActivityIcon(intent.getComponent());
2198 }
2199
2200 ResolveInfo info = resolveActivity(
2201 intent, PackageManager.MATCH_DEFAULT_ONLY);
2202 if (info != null) {
2203 return info.activityInfo.loadIcon(this);
2204 }
2205
2206 throw new NameNotFoundException(intent.toURI());
2207 }
2208
2209 @Override public Drawable getDefaultActivityIcon() {
2210 return Resources.getSystem().getDrawable(
2211 com.android.internal.R.drawable.sym_def_app_icon);
2212 }
2213
2214 @Override public Drawable getApplicationIcon(ApplicationInfo info) {
Jeff Brown07330792010-03-30 19:57:08 -07002215 return info.loadIcon(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 }
2217
2218 @Override public Drawable getApplicationIcon(String packageName)
2219 throws NameNotFoundException {
2220 return getApplicationIcon(getApplicationInfo(packageName, 0));
2221 }
Adam Powell81cd2e92010-04-21 16:35:18 -07002222
2223 @Override
2224 public Drawable getActivityLogo(ComponentName activityName)
2225 throws NameNotFoundException {
2226 return getActivityInfo(activityName, 0).loadLogo(this);
2227 }
2228
2229 @Override
2230 public Drawable getActivityLogo(Intent intent)
2231 throws NameNotFoundException {
2232 if (intent.getComponent() != null) {
2233 return getActivityLogo(intent.getComponent());
2234 }
2235
2236 ResolveInfo info = resolveActivity(
2237 intent, PackageManager.MATCH_DEFAULT_ONLY);
2238 if (info != null) {
2239 return info.activityInfo.loadLogo(this);
2240 }
2241
2242 throw new NameNotFoundException(intent.toUri(0));
2243 }
2244
2245 @Override
2246 public Drawable getApplicationLogo(ApplicationInfo info) {
2247 return info.loadLogo(this);
2248 }
2249
2250 @Override
2251 public Drawable getApplicationLogo(String packageName)
2252 throws NameNotFoundException {
2253 return getApplicationLogo(getApplicationInfo(packageName, 0));
2254 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002255
2256 @Override public Resources getResourcesForActivity(
2257 ComponentName activityName) throws NameNotFoundException {
2258 return getResourcesForApplication(
2259 getActivityInfo(activityName, 0).applicationInfo);
2260 }
2261
2262 @Override public Resources getResourcesForApplication(
2263 ApplicationInfo app) throws NameNotFoundException {
2264 if (app.packageName.equals("system")) {
2265 return mContext.mMainThread.getSystemContext().getResources();
2266 }
2267 Resources r = mContext.mMainThread.getTopLevelResources(
2268 app.uid == Process.myUid() ? app.sourceDir
Dianne Hackborn11ea3342009-07-22 21:48:55 -07002269 : app.publicSourceDir, mContext.mPackageInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002270 if (r != null) {
2271 return r;
2272 }
2273 throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
2274 }
2275
2276 @Override public Resources getResourcesForApplication(
2277 String appPackageName) throws NameNotFoundException {
2278 return getResourcesForApplication(
2279 getApplicationInfo(appPackageName, 0));
2280 }
2281
2282 int mCachedSafeMode = -1;
2283 @Override public boolean isSafeMode() {
2284 try {
2285 if (mCachedSafeMode < 0) {
2286 mCachedSafeMode = mPM.isSafeMode() ? 1 : 0;
2287 }
2288 return mCachedSafeMode != 0;
2289 } catch (RemoteException e) {
2290 throw new RuntimeException("Package manager has died", e);
2291 }
2292 }
2293
2294 static void configurationChanged() {
2295 synchronized (sSync) {
2296 sIconCache.clear();
2297 sStringCache.clear();
2298 }
2299 }
2300
Dianne Hackborn21556372010-02-04 16:34:40 -08002301 ApplicationPackageManager(ContextImpl context,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002302 IPackageManager pm) {
2303 mContext = context;
2304 mPM = pm;
2305 }
2306
2307 private Drawable getCachedIcon(ResourceName name) {
2308 synchronized (sSync) {
2309 WeakReference<Drawable> wr = sIconCache.get(name);
2310 if (DEBUG_ICONS) Log.v(TAG, "Get cached weak drawable ref for "
2311 + name + ": " + wr);
2312 if (wr != null) { // we have the activity
2313 Drawable dr = wr.get();
2314 if (dr != null) {
2315 if (DEBUG_ICONS) Log.v(TAG, "Get cached drawable for "
2316 + name + ": " + dr);
2317 return dr;
2318 }
2319 // our entry has been purged
2320 sIconCache.remove(name);
2321 }
2322 }
2323 return null;
2324 }
2325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002326 private void putCachedIcon(ResourceName name, Drawable dr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002327 synchronized (sSync) {
2328 sIconCache.put(name, new WeakReference<Drawable>(dr));
2329 if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for "
2330 + name + ": " + dr);
2331 }
2332 }
2333
Dianne Hackborn4416c3d2010-05-04 17:22:49 -07002334 static final void handlePackageBroadcast(int cmd, String[] pkgList,
2335 boolean hasPkgInfo) {
2336 boolean immediateGc = false;
2337 if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) {
2338 immediateGc = true;
2339 }
2340 if (pkgList != null && (pkgList.length > 0)) {
2341 boolean needCleanup = false;
2342 for (String ssp : pkgList) {
2343 synchronized (sSync) {
2344 if (sIconCache.size() > 0) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002345 Iterator<ResourceName> it = sIconCache.keySet().iterator();
2346 while (it.hasNext()) {
2347 ResourceName nm = it.next();
2348 if (nm.packageName.equals(ssp)) {
2349 //Log.i(TAG, "Removing cached drawable for " + nm);
2350 it.remove();
2351 needCleanup = true;
2352 }
2353 }
Dianne Hackborn4416c3d2010-05-04 17:22:49 -07002354 }
2355 if (sStringCache.size() > 0) {
2356 Iterator<ResourceName> it = sStringCache.keySet().iterator();
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002357 while (it.hasNext()) {
2358 ResourceName nm = it.next();
2359 if (nm.packageName.equals(ssp)) {
2360 //Log.i(TAG, "Removing cached string for " + nm);
2361 it.remove();
2362 needCleanup = true;
2363 }
2364 }
2365 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002366 }
Dianne Hackborn4416c3d2010-05-04 17:22:49 -07002367 }
2368 if (needCleanup || hasPkgInfo) {
2369 if (immediateGc) {
2370 // Schedule an immediate gc.
2371 Runtime.getRuntime().gc();
2372 } else {
2373 ActivityThread.currentActivityThread().scheduleGcIdler();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002374 }
2375 }
2376 }
2377 }
Dianne Hackborn4416c3d2010-05-04 17:22:49 -07002378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002379 private static final class ResourceName {
2380 final String packageName;
2381 final int iconId;
2382
2383 ResourceName(String _packageName, int _iconId) {
2384 packageName = _packageName;
2385 iconId = _iconId;
2386 }
2387
2388 ResourceName(ApplicationInfo aInfo, int _iconId) {
2389 this(aInfo.packageName, _iconId);
2390 }
2391
2392 ResourceName(ComponentInfo cInfo, int _iconId) {
2393 this(cInfo.applicationInfo.packageName, _iconId);
2394 }
2395
2396 ResourceName(ResolveInfo rInfo, int _iconId) {
2397 this(rInfo.activityInfo.applicationInfo.packageName, _iconId);
2398 }
2399
2400 @Override
2401 public boolean equals(Object o) {
2402 if (this == o) return true;
2403 if (o == null || getClass() != o.getClass()) return false;
2404
2405 ResourceName that = (ResourceName) o;
2406
2407 if (iconId != that.iconId) return false;
2408 return !(packageName != null ?
2409 !packageName.equals(that.packageName) : that.packageName != null);
2410
2411 }
2412
2413 @Override
2414 public int hashCode() {
2415 int result;
2416 result = packageName.hashCode();
2417 result = 31 * result + iconId;
2418 return result;
2419 }
2420
2421 @Override
2422 public String toString() {
2423 return "{ResourceName " + packageName + " / " + iconId + "}";
2424 }
2425 }
2426
2427 private CharSequence getCachedString(ResourceName name) {
2428 synchronized (sSync) {
2429 WeakReference<CharSequence> wr = sStringCache.get(name);
2430 if (wr != null) { // we have the activity
2431 CharSequence cs = wr.get();
2432 if (cs != null) {
2433 return cs;
2434 }
2435 // our entry has been purged
2436 sStringCache.remove(name);
2437 }
2438 }
2439 return null;
2440 }
2441
2442 private void putCachedString(ResourceName name, CharSequence cs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002443 synchronized (sSync) {
2444 sStringCache.put(name, new WeakReference<CharSequence>(cs));
2445 }
2446 }
2447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002448 @Override
2449 public CharSequence getText(String packageName, int resid,
2450 ApplicationInfo appInfo) {
2451 ResourceName name = new ResourceName(packageName, resid);
2452 CharSequence text = getCachedString(name);
2453 if (text != null) {
2454 return text;
2455 }
2456 if (appInfo == null) {
2457 try {
2458 appInfo = getApplicationInfo(packageName, 0);
2459 } catch (NameNotFoundException e) {
2460 return null;
2461 }
2462 }
2463 try {
2464 Resources r = getResourcesForApplication(appInfo);
2465 text = r.getText(resid);
2466 putCachedString(name, text);
2467 return text;
2468 } catch (NameNotFoundException e) {
2469 Log.w("PackageManager", "Failure retrieving resources for"
2470 + appInfo.packageName);
2471 } catch (RuntimeException e) {
2472 // If an exception was thrown, fall through to return
2473 // default icon.
2474 Log.w("PackageManager", "Failure retrieving text 0x"
2475 + Integer.toHexString(resid) + " in package "
2476 + packageName, e);
2477 }
2478 return null;
2479 }
2480
2481 @Override
2482 public XmlResourceParser getXml(String packageName, int resid,
2483 ApplicationInfo appInfo) {
2484 if (appInfo == null) {
2485 try {
2486 appInfo = getApplicationInfo(packageName, 0);
2487 } catch (NameNotFoundException e) {
2488 return null;
2489 }
2490 }
2491 try {
2492 Resources r = getResourcesForApplication(appInfo);
2493 return r.getXml(resid);
2494 } catch (RuntimeException e) {
2495 // If an exception was thrown, fall through to return
2496 // default icon.
2497 Log.w("PackageManager", "Failure retrieving xml 0x"
2498 + Integer.toHexString(resid) + " in package "
2499 + packageName, e);
2500 } catch (NameNotFoundException e) {
2501 Log.w("PackageManager", "Failure retrieving resources for"
2502 + appInfo.packageName);
2503 }
2504 return null;
2505 }
2506
2507 @Override
2508 public CharSequence getApplicationLabel(ApplicationInfo info) {
Jeff Brown07330792010-03-30 19:57:08 -07002509 return info.loadLabel(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002510 }
2511
2512 @Override
Jacek Surazski65e13172009-04-28 15:26:38 +02002513 public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
2514 String installerPackageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002515 try {
Jacek Surazski65e13172009-04-28 15:26:38 +02002516 mPM.installPackage(packageURI, observer, flags, installerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002517 } catch (RemoteException e) {
2518 // Should never happen!
2519 }
2520 }
2521
2522 @Override
Suchi Amalapurapu8946dd32010-02-19 09:19:34 -08002523 public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
2524 try {
2525 mPM.movePackage(packageName, observer, flags);
2526 } catch (RemoteException e) {
2527 // Should never happen!
2528 }
2529 }
2530
2531 @Override
Jacek Surazski65e13172009-04-28 15:26:38 +02002532 public String getInstallerPackageName(String packageName) {
2533 try {
2534 return mPM.getInstallerPackageName(packageName);
2535 } catch (RemoteException e) {
2536 // Should never happen!
2537 }
2538 return null;
2539 }
2540
2541 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002542 public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
2543 try {
2544 mPM.deletePackage(packageName, observer, flags);
2545 } catch (RemoteException e) {
2546 // Should never happen!
2547 }
2548 }
2549 @Override
2550 public void clearApplicationUserData(String packageName,
2551 IPackageDataObserver observer) {
2552 try {
2553 mPM.clearApplicationUserData(packageName, observer);
2554 } catch (RemoteException e) {
2555 // Should never happen!
2556 }
2557 }
2558 @Override
2559 public void deleteApplicationCacheFiles(String packageName,
2560 IPackageDataObserver observer) {
2561 try {
2562 mPM.deleteApplicationCacheFiles(packageName, observer);
2563 } catch (RemoteException e) {
2564 // Should never happen!
2565 }
2566 }
2567 @Override
2568 public void freeStorageAndNotify(long idealStorageSize, IPackageDataObserver observer) {
2569 try {
2570 mPM.freeStorageAndNotify(idealStorageSize, observer);
2571 } catch (RemoteException e) {
2572 // Should never happen!
2573 }
2574 }
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -07002575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002576 @Override
Suchi Amalapurapubc806f62009-06-17 15:18:19 -07002577 public void freeStorage(long freeStorageSize, IntentSender pi) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002578 try {
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -07002579 mPM.freeStorage(freeStorageSize, pi);
2580 } catch (RemoteException e) {
2581 // Should never happen!
2582 }
2583 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002584
2585 @Override
2586 public void getPackageSizeInfo(String packageName,
2587 IPackageStatsObserver observer) {
2588 try {
2589 mPM.getPackageSizeInfo(packageName, observer);
2590 } catch (RemoteException e) {
2591 // Should never happen!
2592 }
2593 }
2594 @Override
2595 public void addPackageToPreferred(String packageName) {
2596 try {
2597 mPM.addPackageToPreferred(packageName);
2598 } catch (RemoteException e) {
2599 // Should never happen!
2600 }
2601 }
2602
2603 @Override
2604 public void removePackageFromPreferred(String packageName) {
2605 try {
2606 mPM.removePackageFromPreferred(packageName);
2607 } catch (RemoteException e) {
2608 // Should never happen!
2609 }
2610 }
2611
2612 @Override
2613 public List<PackageInfo> getPreferredPackages(int flags) {
2614 try {
2615 return mPM.getPreferredPackages(flags);
2616 } catch (RemoteException e) {
2617 // Should never happen!
2618 }
2619 return new ArrayList<PackageInfo>();
2620 }
2621
2622 @Override
2623 public void addPreferredActivity(IntentFilter filter,
2624 int match, ComponentName[] set, ComponentName activity) {
2625 try {
2626 mPM.addPreferredActivity(filter, match, set, activity);
2627 } catch (RemoteException e) {
2628 // Should never happen!
2629 }
2630 }
2631
2632 @Override
Satish Sampath8dbe6122009-06-02 23:35:54 +01002633 public void replacePreferredActivity(IntentFilter filter,
2634 int match, ComponentName[] set, ComponentName activity) {
2635 try {
2636 mPM.replacePreferredActivity(filter, match, set, activity);
2637 } catch (RemoteException e) {
2638 // Should never happen!
2639 }
2640 }
2641
2642 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 public void clearPackagePreferredActivities(String packageName) {
2644 try {
2645 mPM.clearPackagePreferredActivities(packageName);
2646 } catch (RemoteException e) {
2647 // Should never happen!
2648 }
2649 }
2650
2651 @Override
2652 public int getPreferredActivities(List<IntentFilter> outFilters,
2653 List<ComponentName> outActivities, String packageName) {
2654 try {
2655 return mPM.getPreferredActivities(outFilters, outActivities, packageName);
2656 } catch (RemoteException e) {
2657 // Should never happen!
2658 }
2659 return 0;
2660 }
2661
2662 @Override
2663 public void setComponentEnabledSetting(ComponentName componentName,
2664 int newState, int flags) {
2665 try {
2666 mPM.setComponentEnabledSetting(componentName, newState, flags);
2667 } catch (RemoteException e) {
2668 // Should never happen!
2669 }
2670 }
2671
2672 @Override
2673 public int getComponentEnabledSetting(ComponentName componentName) {
2674 try {
2675 return mPM.getComponentEnabledSetting(componentName);
2676 } catch (RemoteException e) {
2677 // Should never happen!
2678 }
2679 return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
2680 }
2681
2682 @Override
2683 public void setApplicationEnabledSetting(String packageName,
2684 int newState, int flags) {
2685 try {
2686 mPM.setApplicationEnabledSetting(packageName, newState, flags);
2687 } catch (RemoteException e) {
2688 // Should never happen!
2689 }
2690 }
2691
2692 @Override
2693 public int getApplicationEnabledSetting(String packageName) {
2694 try {
2695 return mPM.getApplicationEnabledSetting(packageName);
2696 } catch (RemoteException e) {
2697 // Should never happen!
2698 }
2699 return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
2700 }
2701
Kenny Root93565c42010-06-18 15:46:06 -07002702 @Override
2703 public void setPackageObbPath(String packageName, String path) {
2704 try {
2705 mPM.setPackageObbPath(packageName, path);
2706 } catch (RemoteException e) {
2707 // Should never happen!
2708 }
2709 }
2710
Dianne Hackborn21556372010-02-04 16:34:40 -08002711 private final ContextImpl mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002712 private final IPackageManager mPM;
2713
2714 private static final Object sSync = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002715 private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache
2716 = new HashMap<ResourceName, WeakReference<Drawable> >();
2717 private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache
2718 = new HashMap<ResourceName, WeakReference<CharSequence> >();
2719 }
2720
2721 // ----------------------------------------------------------------------
2722 // ----------------------------------------------------------------------
2723 // ----------------------------------------------------------------------
2724
2725 private static final class SharedPreferencesImpl implements SharedPreferences {
2726
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002727 // Lock ordering rules:
2728 // - acquire SharedPreferencesImpl.this before EditorImpl.this
2729 // - acquire mWritingToDiskLock before EditorImpl.this
2730
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002731 private final File mFile;
2732 private final File mBackupFile;
2733 private final int mMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002734
Brad Fitzpatrick9acdeb92010-10-08 15:20:11 -07002735 private Map<String, Object> mMap; // guarded by 'this'
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002736 private int mDiskWritesInFlight = 0; // guarded by 'this'
Brad Fitzpatrick9acdeb92010-10-08 15:20:11 -07002737 private boolean mLoaded = false; // guarded by 'this'
2738 private long mStatTimestamp; // guarded by 'this'
2739 private long mStatSize; // guarded by 'this'
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002740
2741 private final Object mWritingToDiskLock = new Object();
The Android Open Source Project10592532009-03-18 17:39:46 -07002742 private static final Object mContent = new Object();
Brad Fitzpatrick9acdeb92010-10-08 15:20:11 -07002743 private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002744
2745 SharedPreferencesImpl(
2746 File file, int mode, Map initialContents) {
2747 mFile = file;
2748 mBackupFile = makeBackupFile(file);
2749 mMode = mode;
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002750 mLoaded = initialContents != null;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002751 mMap = initialContents != null ? initialContents : new HashMap<String, Object>();
2752 FileStatus stat = new FileStatus();
2753 if (FileUtils.getFileStatus(file.getPath(), stat)) {
Brad Fitzpatrick9acdeb92010-10-08 15:20:11 -07002754 mStatTimestamp = stat.mtime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002755 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002756 mListeners = new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002757 }
2758
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002759 // Has this SharedPreferences ever had values assigned to it?
2760 boolean isLoaded() {
2761 synchronized (this) {
2762 return mLoaded;
2763 }
2764 }
2765
2766 // Has the file changed out from under us? i.e. writes that
2767 // we didn't instigate.
2768 public boolean hasFileChangedUnexpectedly() {
2769 synchronized (this) {
2770 if (mDiskWritesInFlight > 0) {
2771 // If we know we caused it, it's not unexpected.
Brad Fitzpatrick90bc5ee2010-10-07 11:26:57 -07002772 if (DEBUG) Log.d(TAG, "disk write in flight, not unexpected.");
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002773 return false;
2774 }
2775 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002776 FileStatus stat = new FileStatus();
2777 if (!FileUtils.getFileStatus(mFile.getPath(), stat)) {
2778 return true;
2779 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002780 synchronized (this) {
Brad Fitzpatrick9acdeb92010-10-08 15:20:11 -07002781 return mStatTimestamp != stat.mtime || mStatSize != stat.size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002782 }
2783 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002784
Brad Fitzpatrickd2bbaaf2010-11-30 12:59:28 -08002785 /* package */ void replace(Map newContents, FileStatus stat) {
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002786 synchronized (this) {
2787 mLoaded = true;
2788 if (newContents != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002789 mMap = newContents;
2790 }
Brad Fitzpatrickd2bbaaf2010-11-30 12:59:28 -08002791 if (stat != null) {
2792 mStatTimestamp = stat.mtime;
2793 mStatSize = stat.size;
2794 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002795 }
2796 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002798 public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
2799 synchronized(this) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002800 mListeners.put(listener, mContent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002801 }
2802 }
2803
2804 public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
2805 synchronized(this) {
2806 mListeners.remove(listener);
2807 }
2808 }
2809
2810 public Map<String, ?> getAll() {
2811 synchronized(this) {
2812 //noinspection unchecked
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002813 return new HashMap<String, Object>(mMap);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002814 }
2815 }
2816
2817 public String getString(String key, String defValue) {
2818 synchronized (this) {
2819 String v = (String)mMap.get(key);
2820 return v != null ? v : defValue;
2821 }
2822 }
2823
2824 public int getInt(String key, int defValue) {
2825 synchronized (this) {
2826 Integer v = (Integer)mMap.get(key);
2827 return v != null ? v : defValue;
2828 }
2829 }
2830 public long getLong(String key, long defValue) {
2831 synchronized (this) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002832 Long v = (Long)mMap.get(key);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002833 return v != null ? v : defValue;
2834 }
2835 }
2836 public float getFloat(String key, float defValue) {
2837 synchronized (this) {
2838 Float v = (Float)mMap.get(key);
2839 return v != null ? v : defValue;
2840 }
2841 }
2842 public boolean getBoolean(String key, boolean defValue) {
2843 synchronized (this) {
2844 Boolean v = (Boolean)mMap.get(key);
2845 return v != null ? v : defValue;
2846 }
2847 }
2848
2849 public boolean contains(String key) {
2850 synchronized (this) {
2851 return mMap.containsKey(key);
2852 }
2853 }
2854
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002855 public Editor edit() {
2856 return new EditorImpl();
2857 }
2858
2859 // Return value from EditorImpl#commitToMemory()
2860 private static class MemoryCommitResult {
2861 public boolean changesMade; // any keys different?
2862 public List<String> keysModified; // may be null
2863 public Set<OnSharedPreferenceChangeListener> listeners; // may be null
2864 public Map<?, ?> mapToWriteToDisk;
2865 public final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
2866 public volatile boolean writeToDiskResult = false;
2867
2868 public void setDiskWriteResult(boolean result) {
2869 writeToDiskResult = result;
2870 writtenToDiskLatch.countDown();
2871 }
2872 }
2873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002874 public final class EditorImpl implements Editor {
2875 private final Map<String, Object> mModified = Maps.newHashMap();
2876 private boolean mClear = false;
2877
2878 public Editor putString(String key, String value) {
2879 synchronized (this) {
2880 mModified.put(key, value);
2881 return this;
2882 }
2883 }
2884 public Editor putInt(String key, int value) {
2885 synchronized (this) {
2886 mModified.put(key, value);
2887 return this;
2888 }
2889 }
2890 public Editor putLong(String key, long value) {
2891 synchronized (this) {
2892 mModified.put(key, value);
2893 return this;
2894 }
2895 }
2896 public Editor putFloat(String key, float value) {
2897 synchronized (this) {
2898 mModified.put(key, value);
2899 return this;
2900 }
2901 }
2902 public Editor putBoolean(String key, boolean value) {
2903 synchronized (this) {
2904 mModified.put(key, value);
2905 return this;
2906 }
2907 }
2908
2909 public Editor remove(String key) {
2910 synchronized (this) {
2911 mModified.put(key, this);
2912 return this;
2913 }
2914 }
2915
2916 public Editor clear() {
2917 synchronized (this) {
2918 mClear = true;
2919 return this;
2920 }
2921 }
2922
Brad Fitzpatrick66fce502010-08-30 18:10:49 -07002923 public void apply() {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002924 final MemoryCommitResult mcr = commitToMemory();
2925 final Runnable awaitCommit = new Runnable() {
2926 public void run() {
2927 try {
2928 mcr.writtenToDiskLatch.await();
2929 } catch (InterruptedException ignored) {
2930 }
2931 }
2932 };
2933
2934 QueuedWork.add(awaitCommit);
2935
2936 Runnable postWriteRunnable = new Runnable() {
2937 public void run() {
2938 awaitCommit.run();
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002939 QueuedWork.remove(awaitCommit);
2940 }
2941 };
2942
2943 SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
2944
2945 // Okay to notify the listeners before it's hit disk
2946 // because the listeners should always get the same
2947 // SharedPreferences instance back, which has the
2948 // changes reflected in memory.
2949 notifyListeners(mcr);
Brad Fitzpatrickedf32d02010-08-25 13:13:36 -07002950 }
2951
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002952 // Returns true if any changes were made
2953 private MemoryCommitResult commitToMemory() {
2954 MemoryCommitResult mcr = new MemoryCommitResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002955 synchronized (SharedPreferencesImpl.this) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002956 // We optimistically don't make a deep copy until
2957 // a memory commit comes in when we're already
2958 // writing to disk.
2959 if (mDiskWritesInFlight > 0) {
2960 // We can't modify our mMap as a currently
2961 // in-flight write owns it. Clone it before
2962 // modifying it.
2963 // noinspection unchecked
2964 mMap = new HashMap<String, Object>(mMap);
2965 }
2966 mcr.mapToWriteToDisk = mMap;
2967 mDiskWritesInFlight++;
2968
2969 boolean hasListeners = mListeners.size() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002970 if (hasListeners) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002971 mcr.keysModified = new ArrayList<String>();
2972 mcr.listeners =
2973 new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002974 }
2975
2976 synchronized (this) {
2977 if (mClear) {
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002978 if (!mMap.isEmpty()) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002979 mcr.changesMade = true;
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002980 mMap.clear();
2981 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002982 mClear = false;
2983 }
2984
The Android Open Source Project10592532009-03-18 17:39:46 -07002985 for (Entry<String, Object> e : mModified.entrySet()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002986 String k = e.getKey();
2987 Object v = e.getValue();
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002988 if (v == this) { // magic value for a removal mutation
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002989 if (!mMap.containsKey(k)) {
2990 continue;
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002991 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002992 mMap.remove(k);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002993 } else {
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002994 boolean isSame = false;
2995 if (mMap.containsKey(k)) {
2996 Object existingValue = mMap.get(k);
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002997 if (existingValue != null && existingValue.equals(v)) {
2998 continue;
2999 }
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07003000 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003001 mMap.put(k, v);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003002 }
3003
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003004 mcr.changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003005 if (hasListeners) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003006 mcr.keysModified.add(k);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003007 }
3008 }
3009
3010 mModified.clear();
3011 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003012 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003013 return mcr;
3014 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003015
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003016 public boolean commit() {
3017 MemoryCommitResult mcr = commitToMemory();
3018 SharedPreferencesImpl.this.enqueueDiskWrite(
3019 mcr, null /* sync write on this thread okay */);
3020 try {
3021 mcr.writtenToDiskLatch.await();
3022 } catch (InterruptedException e) {
3023 return false;
3024 }
3025 notifyListeners(mcr);
3026 return mcr.writeToDiskResult;
3027 }
3028
3029 private void notifyListeners(final MemoryCommitResult mcr) {
3030 if (mcr.listeners == null || mcr.keysModified == null ||
3031 mcr.keysModified.size() == 0) {
3032 return;
3033 }
3034 if (Looper.myLooper() == Looper.getMainLooper()) {
3035 for (int i = mcr.keysModified.size() - 1; i >= 0; i--) {
3036 final String key = mcr.keysModified.get(i);
3037 for (OnSharedPreferenceChangeListener listener : mcr.listeners) {
The Android Open Source Project10592532009-03-18 17:39:46 -07003038 if (listener != null) {
3039 listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key);
3040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003041 }
3042 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003043 } else {
3044 // Run this function on the main thread.
3045 ActivityThread.sMainThreadHandler.post(new Runnable() {
3046 public void run() {
3047 notifyListeners(mcr);
3048 }
3049 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003050 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003051 }
3052 }
3053
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003054 /**
3055 * Enqueue an already-committed-to-memory result to be written
3056 * to disk.
3057 *
3058 * They will be written to disk one-at-a-time in the order
3059 * that they're enqueued.
3060 *
3061 * @param postWriteRunnable if non-null, we're being called
Brad Fitzpatrick66fce502010-08-30 18:10:49 -07003062 * from apply() and this is the runnable to run after
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003063 * the write proceeds. if null (from a regular commit()),
3064 * then we're allowed to do this disk write on the main
3065 * thread (which in addition to reducing allocations and
3066 * creating a background thread, this has the advantage that
3067 * we catch them in userdebug StrictMode reports to convert
Brad Fitzpatrick66fce502010-08-30 18:10:49 -07003068 * them where possible to apply() ...)
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003069 */
3070 private void enqueueDiskWrite(final MemoryCommitResult mcr,
3071 final Runnable postWriteRunnable) {
3072 final Runnable writeToDiskRunnable = new Runnable() {
3073 public void run() {
3074 synchronized (mWritingToDiskLock) {
3075 writeToFile(mcr);
3076 }
3077 synchronized (SharedPreferencesImpl.this) {
3078 mDiskWritesInFlight--;
3079 }
3080 if (postWriteRunnable != null) {
3081 postWriteRunnable.run();
3082 }
3083 }
3084 };
3085
3086 final boolean isFromSyncCommit = (postWriteRunnable == null);
3087
3088 // Typical #commit() path with fewer allocations, doing a write on
3089 // the current thread.
3090 if (isFromSyncCommit) {
3091 boolean wasEmpty = false;
3092 synchronized (SharedPreferencesImpl.this) {
3093 wasEmpty = mDiskWritesInFlight == 1;
3094 }
3095 if (wasEmpty) {
3096 writeToDiskRunnable.run();
3097 return;
3098 }
3099 }
3100
3101 QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 }
Brad Fitzpatrickedf32d02010-08-25 13:13:36 -07003103
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003104 private static FileOutputStream createFileOutputStream(File file) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003105 FileOutputStream str = null;
3106 try {
3107 str = new FileOutputStream(file);
3108 } catch (FileNotFoundException e) {
3109 File parent = file.getParentFile();
3110 if (!parent.mkdir()) {
3111 Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file);
3112 return null;
3113 }
3114 FileUtils.setPermissions(
3115 parent.getPath(),
3116 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
3117 -1, -1);
3118 try {
3119 str = new FileOutputStream(file);
3120 } catch (FileNotFoundException e2) {
3121 Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2);
3122 }
3123 }
3124 return str;
3125 }
3126
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003127 // Note: must hold mWritingToDiskLock
3128 private void writeToFile(MemoryCommitResult mcr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003129 // Rename the current file so it may be used as a backup during the next read
3130 if (mFile.exists()) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003131 if (!mcr.changesMade) {
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07003132 // If the file already exists, but no changes were
3133 // made to the underlying map, it's wasteful to
3134 // re-write the file. Return as if we wrote it
3135 // out.
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003136 mcr.setDiskWriteResult(true);
3137 return;
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07003138 }
Dianne Hackborn1afd1c92010-03-18 22:47:17 -07003139 if (!mBackupFile.exists()) {
3140 if (!mFile.renameTo(mBackupFile)) {
3141 Log.e(TAG, "Couldn't rename file " + mFile
3142 + " to backup file " + mBackupFile);
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003143 mcr.setDiskWriteResult(false);
3144 return;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -07003145 }
3146 } else {
3147 mFile.delete();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003148 }
3149 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003151 // Attempt to write the file, delete the backup and return true as atomically as
3152 // possible. If any exception occurs, delete the new file; next time we will restore
3153 // from the backup.
3154 try {
3155 FileOutputStream str = createFileOutputStream(mFile);
3156 if (str == null) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003157 mcr.setDiskWriteResult(false);
3158 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003159 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003160 XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);
Dianne Hackborn8bdf5932010-10-15 12:54:40 -07003161 FileUtils.sync(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003162 str.close();
3163 setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003164 FileStatus stat = new FileStatus();
3165 if (FileUtils.getFileStatus(mFile.getPath(), stat)) {
3166 synchronized (this) {
Brad Fitzpatrick9acdeb92010-10-08 15:20:11 -07003167 mStatTimestamp = stat.mtime;
3168 mStatSize = stat.size;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003169 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003170 }
Dianne Hackborn51bf0772009-03-24 19:11:41 -07003171 // Writing was successful, delete the backup file if there is one.
3172 mBackupFile.delete();
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003173 mcr.setDiskWriteResult(true);
3174 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003175 } catch (XmlPullParserException e) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003176 Log.w(TAG, "writeToFile: Got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003177 } catch (IOException e) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003178 Log.w(TAG, "writeToFile: Got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 }
3180 // Clean up an unsuccessfully written file
3181 if (mFile.exists()) {
3182 if (!mFile.delete()) {
3183 Log.e(TAG, "Couldn't clean up partially-written file " + mFile);
3184 }
3185 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003186 mcr.setDiskWriteResult(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187 }
3188 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003189}