summaryrefslogtreecommitdiffstats
path: root/core/java/android/app/ContextImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/app/ContextImpl.java')
-rw-r--r--core/java/android/app/ContextImpl.java2913
1 files changed, 2913 insertions, 0 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
new file mode 100644
index 0000000..f471f57
--- /dev/null
+++ b/core/java/android/app/ContextImpl.java
@@ -0,0 +1,2913 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import com.android.internal.policy.PolicyManager;
+import com.android.internal.util.XmlUtils;
+import com.google.android.collect.Maps;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.IContentProvider;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IIntentReceiver;
+import android.content.IntentSender;
+import android.content.ReceiverCallNotAllowedException;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageInstallObserver;
+import android.content.pm.IPackageMoveObserver;
+import android.content.pm.IPackageManager;
+import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.PackageParser.Package;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabase.CursorFactory;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.hardware.SensorManager;
+import android.location.ILocationManager;
+import android.location.LocationManager;
+import android.media.AudioManager;
+import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
+import android.net.ThrottleManager;
+import android.net.IThrottleManager;
+import android.net.Uri;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.WifiManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.DropBoxManager;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.StatFs;
+import android.os.Vibrator;
+import android.os.FileUtils.FileStatus;
+import android.os.storage.StorageManager;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.text.ClipboardManager;
+import android.util.AndroidRuntimeException;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.WindowManagerImpl;
+import android.view.accessibility.AccessibilityManager;
+import android.view.inputmethod.InputMethodManager;
+import android.accounts.AccountManager;
+import android.accounts.IAccountManager;
+import android.app.admin.DevicePolicyManager;
+
+import com.android.internal.os.IDropBoxManagerService;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.Map.Entry;
+
+class ReceiverRestrictedContext extends ContextWrapper {
+ ReceiverRestrictedContext(Context base) {
+ super(base);
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ return registerReceiver(receiver, filter, null, null);
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+ String broadcastPermission, Handler scheduler) {
+ throw new ReceiverCallNotAllowedException(
+ "IntentReceiver components are not allowed to register to receive intents");
+ //ex.fillInStackTrace();
+ //Log.e("IntentReceiver", ex.getMessage(), ex);
+ //return mContext.registerReceiver(receiver, filter, broadcastPermission,
+ // scheduler);
+ }
+
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags) {
+ throw new ReceiverCallNotAllowedException(
+ "IntentReceiver components are not allowed to bind to services");
+ //ex.fillInStackTrace();
+ //Log.e("IntentReceiver", ex.getMessage(), ex);
+ //return mContext.bindService(service, interfaceName, conn, flags);
+ }
+}
+
+/**
+ * Common implementation of Context API, which provides the base
+ * context object for Activity and other application components.
+ */
+class ContextImpl extends Context {
+ private final static String TAG = "ApplicationContext";
+ private final static boolean DEBUG = false;
+ private final static boolean DEBUG_ICONS = false;
+
+ private static final Object sSync = new Object();
+ private static AlarmManager sAlarmManager;
+ private static PowerManager sPowerManager;
+ private static ConnectivityManager sConnectivityManager;
+ private static ThrottleManager sThrottleManager;
+ private static WifiManager sWifiManager;
+ private static LocationManager sLocationManager;
+ private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs =
+ new HashMap<File, SharedPreferencesImpl>();
+
+ private AudioManager mAudioManager;
+ /*package*/ ActivityThread.PackageInfo mPackageInfo;
+ private Resources mResources;
+ /*package*/ ActivityThread mMainThread;
+ private Context mOuterContext;
+ private IBinder mActivityToken = null;
+ private ApplicationContentResolver mContentResolver;
+ private int mThemeResource = 0;
+ private Resources.Theme mTheme = null;
+ private PackageManager mPackageManager;
+ private NotificationManager mNotificationManager = null;
+ private ActivityManager mActivityManager = null;
+ private WallpaperManager mWallpaperManager = null;
+ private Context mReceiverRestrictedContext = null;
+ private SearchManager mSearchManager = null;
+ private SensorManager mSensorManager = null;
+ private StorageManager mStorageManager = null;
+ private Vibrator mVibrator = null;
+ private LayoutInflater mLayoutInflater = null;
+ private StatusBarManager mStatusBarManager = null;
+ private TelephonyManager mTelephonyManager = null;
+ private ClipboardManager mClipboardManager = null;
+ private boolean mRestricted;
+ private AccountManager mAccountManager; // protected by mSync
+ private DropBoxManager mDropBoxManager = null;
+ private DevicePolicyManager mDevicePolicyManager = null;
+ private UiModeManager mUiModeManager = null;
+
+ private final Object mSync = new Object();
+
+ private File mDatabasesDir;
+ private File mPreferencesDir;
+ private File mFilesDir;
+ private File mCacheDir;
+ private File mExternalFilesDir;
+ private File mExternalCacheDir;
+
+ private static long sInstanceCount = 0;
+
+ private static final String[] EMPTY_FILE_LIST = {};
+
+ // For debug only
+ /*
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ --sInstanceCount;
+ }
+ */
+
+ public static long getInstanceCount() {
+ return sInstanceCount;
+ }
+
+ @Override
+ public AssetManager getAssets() {
+ return mResources.getAssets();
+ }
+
+ @Override
+ public Resources getResources() {
+ return mResources;
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ if (mPackageManager != null) {
+ return mPackageManager;
+ }
+
+ IPackageManager pm = ActivityThread.getPackageManager();
+ if (pm != null) {
+ // Doesn't matter if we make more than one instance.
+ return (mPackageManager = new ApplicationPackageManager(this, pm));
+ }
+
+ return null;
+ }
+
+ @Override
+ public ContentResolver getContentResolver() {
+ return mContentResolver;
+ }
+
+ @Override
+ public Looper getMainLooper() {
+ return mMainThread.getLooper();
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ return (mPackageInfo != null) ?
+ mPackageInfo.getApplication() : mMainThread.getApplication();
+ }
+
+ @Override
+ public void setTheme(int resid) {
+ mThemeResource = resid;
+ }
+
+ @Override
+ public Resources.Theme getTheme() {
+ if (mTheme == null) {
+ if (mThemeResource == 0) {
+ mThemeResource = com.android.internal.R.style.Theme;
+ }
+ mTheme = mResources.newTheme();
+ mTheme.applyStyle(mThemeResource, true);
+ }
+ return mTheme;
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ return mPackageInfo != null ?
+ mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader();
+ }
+
+ @Override
+ public String getPackageName() {
+ if (mPackageInfo != null) {
+ return mPackageInfo.getPackageName();
+ }
+ throw new RuntimeException("Not supported in system context");
+ }
+
+ @Override
+ public ApplicationInfo getApplicationInfo() {
+ if (mPackageInfo != null) {
+ return mPackageInfo.getApplicationInfo();
+ }
+ throw new RuntimeException("Not supported in system context");
+ }
+
+ @Override
+ public String getPackageResourcePath() {
+ if (mPackageInfo != null) {
+ return mPackageInfo.getResDir();
+ }
+ throw new RuntimeException("Not supported in system context");
+ }
+
+ @Override
+ public String getPackageCodePath() {
+ if (mPackageInfo != null) {
+ return mPackageInfo.getAppDir();
+ }
+ throw new RuntimeException("Not supported in system context");
+ }
+
+ private static File makeBackupFile(File prefsFile) {
+ return new File(prefsFile.getPath() + ".bak");
+ }
+
+ public File getSharedPrefsFile(String name) {
+ return makeFilename(getPreferencesDir(), name + ".xml");
+ }
+
+ @Override
+ public SharedPreferences getSharedPreferences(String name, int mode) {
+ SharedPreferencesImpl sp;
+ File f = getSharedPrefsFile(name);
+ synchronized (sSharedPrefs) {
+ sp = sSharedPrefs.get(f);
+ if (sp != null && !sp.hasFileChanged()) {
+ //Log.i(TAG, "Returning existing prefs " + name + ": " + sp);
+ return sp;
+ }
+ }
+
+ FileInputStream str = null;
+ File backup = makeBackupFile(f);
+ if (backup.exists()) {
+ f.delete();
+ backup.renameTo(f);
+ }
+
+ // Debugging
+ if (f.exists() && !f.canRead()) {
+ Log.w(TAG, "Attempt to read preferences file " + f + " without permission");
+ }
+
+ Map map = null;
+ if (f.exists() && f.canRead()) {
+ try {
+ str = new FileInputStream(f);
+ map = XmlUtils.readMapXml(str);
+ str.close();
+ } catch (org.xmlpull.v1.XmlPullParserException e) {
+ Log.w(TAG, "getSharedPreferences", e);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "getSharedPreferences", e);
+ } catch (IOException e) {
+ Log.w(TAG, "getSharedPreferences", e);
+ }
+ }
+
+ synchronized (sSharedPrefs) {
+ if (sp != null) {
+ //Log.i(TAG, "Updating existing prefs " + name + " " + sp + ": " + map);
+ sp.replace(map);
+ } else {
+ sp = sSharedPrefs.get(f);
+ if (sp == null) {
+ sp = new SharedPreferencesImpl(f, mode, map);
+ sSharedPrefs.put(f, sp);
+ }
+ }
+ return sp;
+ }
+ }
+
+ private File getPreferencesDir() {
+ synchronized (mSync) {
+ if (mPreferencesDir == null) {
+ mPreferencesDir = new File(getDataDirFile(), "shared_prefs");
+ }
+ return mPreferencesDir;
+ }
+ }
+
+ @Override
+ public FileInputStream openFileInput(String name)
+ throws FileNotFoundException {
+ File f = makeFilename(getFilesDir(), name);
+ return new FileInputStream(f);
+ }
+
+ @Override
+ public FileOutputStream openFileOutput(String name, int mode)
+ throws FileNotFoundException {
+ final boolean append = (mode&MODE_APPEND) != 0;
+ File f = makeFilename(getFilesDir(), name);
+ try {
+ FileOutputStream fos = new FileOutputStream(f, append);
+ setFilePermissionsFromMode(f.getPath(), mode, 0);
+ return fos;
+ } catch (FileNotFoundException e) {
+ }
+
+ File parent = f.getParentFile();
+ parent.mkdir();
+ FileUtils.setPermissions(
+ parent.getPath(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+ -1, -1);
+ FileOutputStream fos = new FileOutputStream(f, append);
+ setFilePermissionsFromMode(f.getPath(), mode, 0);
+ return fos;
+ }
+
+ @Override
+ public boolean deleteFile(String name) {
+ File f = makeFilename(getFilesDir(), name);
+ return f.delete();
+ }
+
+ @Override
+ public File getFilesDir() {
+ synchronized (mSync) {
+ if (mFilesDir == null) {
+ mFilesDir = new File(getDataDirFile(), "files");
+ }
+ if (!mFilesDir.exists()) {
+ if(!mFilesDir.mkdirs()) {
+ Log.w(TAG, "Unable to create files directory");
+ return null;
+ }
+ FileUtils.setPermissions(
+ mFilesDir.getPath(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+ -1, -1);
+ }
+ return mFilesDir;
+ }
+ }
+
+ @Override
+ public File getExternalFilesDir(String type) {
+ synchronized (mSync) {
+ if (mExternalFilesDir == null) {
+ mExternalFilesDir = Environment.getExternalStorageAppFilesDirectory(
+ getPackageName());
+ }
+ if (!mExternalFilesDir.exists()) {
+ try {
+ (new File(Environment.getExternalStorageAndroidDataDir(),
+ ".nomedia")).createNewFile();
+ } catch (IOException e) {
+ }
+ if (!mExternalFilesDir.mkdirs()) {
+ Log.w(TAG, "Unable to create external files directory");
+ return null;
+ }
+ }
+ if (type == null) {
+ return mExternalFilesDir;
+ }
+ File dir = new File(mExternalFilesDir, type);
+ if (!dir.exists()) {
+ if (!dir.mkdirs()) {
+ Log.w(TAG, "Unable to create external media directory " + dir);
+ return null;
+ }
+ }
+ return dir;
+ }
+ }
+
+ @Override
+ public File getCacheDir() {
+ synchronized (mSync) {
+ if (mCacheDir == null) {
+ mCacheDir = new File(getDataDirFile(), "cache");
+ }
+ if (!mCacheDir.exists()) {
+ if(!mCacheDir.mkdirs()) {
+ Log.w(TAG, "Unable to create cache directory");
+ return null;
+ }
+ FileUtils.setPermissions(
+ mCacheDir.getPath(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+ -1, -1);
+ }
+ }
+ return mCacheDir;
+ }
+
+ @Override
+ public File getExternalCacheDir() {
+ synchronized (mSync) {
+ if (mExternalCacheDir == null) {
+ mExternalCacheDir = Environment.getExternalStorageAppCacheDirectory(
+ getPackageName());
+ }
+ if (!mExternalCacheDir.exists()) {
+ try {
+ (new File(Environment.getExternalStorageAndroidDataDir(),
+ ".nomedia")).createNewFile();
+ } catch (IOException e) {
+ }
+ if (!mExternalCacheDir.mkdirs()) {
+ Log.w(TAG, "Unable to create external cache directory");
+ return null;
+ }
+ }
+ return mExternalCacheDir;
+ }
+ }
+
+ @Override
+ public File getFileStreamPath(String name) {
+ return makeFilename(getFilesDir(), name);
+ }
+
+ @Override
+ public String[] fileList() {
+ final String[] list = getFilesDir().list();
+ return (list != null) ? list : EMPTY_FILE_LIST;
+ }
+
+ @Override
+ public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
+ File f = validateFilePath(name, true);
+ SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory);
+ setFilePermissionsFromMode(f.getPath(), mode, 0);
+ return db;
+ }
+
+ @Override
+ public boolean deleteDatabase(String name) {
+ try {
+ File f = validateFilePath(name, false);
+ return f.delete();
+ } catch (Exception e) {
+ }
+ return false;
+ }
+
+ @Override
+ public File getDatabasePath(String name) {
+ return validateFilePath(name, false);
+ }
+
+ @Override
+ public String[] databaseList() {
+ final String[] list = getDatabasesDir().list();
+ return (list != null) ? list : EMPTY_FILE_LIST;
+ }
+
+
+ private File getDatabasesDir() {
+ synchronized (mSync) {
+ if (mDatabasesDir == null) {
+ mDatabasesDir = new File(getDataDirFile(), "databases");
+ }
+ if (mDatabasesDir.getPath().equals("databases")) {
+ mDatabasesDir = new File("/data/system");
+ }
+ return mDatabasesDir;
+ }
+ }
+
+ @Override
+ public Drawable getWallpaper() {
+ return getWallpaperManager().getDrawable();
+ }
+
+ @Override
+ public Drawable peekWallpaper() {
+ return getWallpaperManager().peekDrawable();
+ }
+
+ @Override
+ public int getWallpaperDesiredMinimumWidth() {
+ return getWallpaperManager().getDesiredMinimumWidth();
+ }
+
+ @Override
+ public int getWallpaperDesiredMinimumHeight() {
+ return getWallpaperManager().getDesiredMinimumHeight();
+ }
+
+ @Override
+ public void setWallpaper(Bitmap bitmap) throws IOException {
+ getWallpaperManager().setBitmap(bitmap);
+ }
+
+ @Override
+ public void setWallpaper(InputStream data) throws IOException {
+ getWallpaperManager().setStream(data);
+ }
+
+ @Override
+ public void clearWallpaper() throws IOException {
+ getWallpaperManager().clear();
+ }
+
+ @Override
+ public void startActivity(Intent intent) {
+ if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
+ throw new AndroidRuntimeException(
+ "Calling startActivity() from outside of an Activity "
+ + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ + " Is this really what you want?");
+ }
+ mMainThread.getInstrumentation().execStartActivity(
+ getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);
+ }
+
+ @Override
+ public void startIntentSender(IntentSender intent,
+ Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
+ throws IntentSender.SendIntentException {
+ try {
+ String resolvedType = null;
+ if (fillInIntent != null) {
+ resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
+ }
+ int result = ActivityManagerNative.getDefault()
+ .startActivityIntentSender(mMainThread.getApplicationThread(), intent,
+ fillInIntent, resolvedType, null, null,
+ 0, flagsMask, flagsValues);
+ if (result == IActivityManager.START_CANCELED) {
+ throw new IntentSender.SendIntentException();
+ }
+ Instrumentation.checkStartActivityResult(result, null);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void sendBroadcast(Intent intent) {
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ ActivityManagerNative.getDefault().broadcastIntent(
+ mMainThread.getApplicationThread(), intent, resolvedType, null,
+ Activity.RESULT_OK, null, null, null, false, false);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void sendBroadcast(Intent intent, String receiverPermission) {
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ ActivityManagerNative.getDefault().broadcastIntent(
+ mMainThread.getApplicationThread(), intent, resolvedType, null,
+ Activity.RESULT_OK, null, null, receiverPermission, false, false);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void sendOrderedBroadcast(Intent intent,
+ String receiverPermission) {
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ ActivityManagerNative.getDefault().broadcastIntent(
+ mMainThread.getApplicationThread(), intent, resolvedType, null,
+ Activity.RESULT_OK, null, null, receiverPermission, true, false);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void sendOrderedBroadcast(Intent intent,
+ String receiverPermission, BroadcastReceiver resultReceiver,
+ Handler scheduler, int initialCode, String initialData,
+ Bundle initialExtras) {
+ IIntentReceiver rd = null;
+ if (resultReceiver != null) {
+ if (mPackageInfo != null) {
+ if (scheduler == null) {
+ scheduler = mMainThread.getHandler();
+ }
+ rd = mPackageInfo.getReceiverDispatcher(
+ resultReceiver, getOuterContext(), scheduler,
+ mMainThread.getInstrumentation(), false);
+ } else {
+ if (scheduler == null) {
+ scheduler = mMainThread.getHandler();
+ }
+ rd = new ActivityThread.PackageInfo.ReceiverDispatcher(
+ resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
+ }
+ }
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ ActivityManagerNative.getDefault().broadcastIntent(
+ mMainThread.getApplicationThread(), intent, resolvedType, rd,
+ initialCode, initialData, initialExtras, receiverPermission,
+ true, false);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void sendStickyBroadcast(Intent intent) {
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ ActivityManagerNative.getDefault().broadcastIntent(
+ mMainThread.getApplicationThread(), intent, resolvedType, null,
+ Activity.RESULT_OK, null, null, null, false, true);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void sendStickyOrderedBroadcast(Intent intent,
+ BroadcastReceiver resultReceiver,
+ Handler scheduler, int initialCode, String initialData,
+ Bundle initialExtras) {
+ IIntentReceiver rd = null;
+ if (resultReceiver != null) {
+ if (mPackageInfo != null) {
+ if (scheduler == null) {
+ scheduler = mMainThread.getHandler();
+ }
+ rd = mPackageInfo.getReceiverDispatcher(
+ resultReceiver, getOuterContext(), scheduler,
+ mMainThread.getInstrumentation(), false);
+ } else {
+ if (scheduler == null) {
+ scheduler = mMainThread.getHandler();
+ }
+ rd = new ActivityThread.PackageInfo.ReceiverDispatcher(
+ resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
+ }
+ }
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ ActivityManagerNative.getDefault().broadcastIntent(
+ mMainThread.getApplicationThread(), intent, resolvedType, rd,
+ initialCode, initialData, initialExtras, null,
+ true, true);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void removeStickyBroadcast(Intent intent) {
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ if (resolvedType != null) {
+ intent = new Intent(intent);
+ intent.setDataAndType(intent.getData(), resolvedType);
+ }
+ try {
+ ActivityManagerNative.getDefault().unbroadcastIntent(
+ mMainThread.getApplicationThread(), intent);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ return registerReceiver(receiver, filter, null, null);
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+ String broadcastPermission, Handler scheduler) {
+ return registerReceiverInternal(receiver, filter, broadcastPermission,
+ scheduler, getOuterContext());
+ }
+
+ private Intent registerReceiverInternal(BroadcastReceiver receiver,
+ IntentFilter filter, String broadcastPermission,
+ Handler scheduler, Context context) {
+ IIntentReceiver rd = null;
+ if (receiver != null) {
+ if (mPackageInfo != null && context != null) {
+ if (scheduler == null) {
+ scheduler = mMainThread.getHandler();
+ }
+ rd = mPackageInfo.getReceiverDispatcher(
+ receiver, context, scheduler,
+ mMainThread.getInstrumentation(), true);
+ } else {
+ if (scheduler == null) {
+ scheduler = mMainThread.getHandler();
+ }
+ rd = new ActivityThread.PackageInfo.ReceiverDispatcher(
+ receiver, context, scheduler, null, true).getIIntentReceiver();
+ }
+ }
+ try {
+ return ActivityManagerNative.getDefault().registerReceiver(
+ mMainThread.getApplicationThread(),
+ rd, filter, broadcastPermission);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public void unregisterReceiver(BroadcastReceiver receiver) {
+ if (mPackageInfo != null) {
+ IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
+ getOuterContext(), receiver);
+ try {
+ ActivityManagerNative.getDefault().unregisterReceiver(rd);
+ } catch (RemoteException e) {
+ }
+ } else {
+ throw new RuntimeException("Not supported in system context");
+ }
+ }
+
+ @Override
+ public ComponentName startService(Intent service) {
+ try {
+ ComponentName cn = ActivityManagerNative.getDefault().startService(
+ mMainThread.getApplicationThread(), service,
+ service.resolveTypeIfNeeded(getContentResolver()));
+ if (cn != null && cn.getPackageName().equals("!")) {
+ throw new SecurityException(
+ "Not allowed to start service " + service
+ + " without permission " + cn.getClassName());
+ }
+ return cn;
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean stopService(Intent service) {
+ try {
+ int res = ActivityManagerNative.getDefault().stopService(
+ mMainThread.getApplicationThread(), service,
+ service.resolveTypeIfNeeded(getContentResolver()));
+ if (res < 0) {
+ throw new SecurityException(
+ "Not allowed to stop service " + service);
+ }
+ return res != 0;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn,
+ int flags) {
+ IServiceConnection sd;
+ if (mPackageInfo != null) {
+ sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
+ mMainThread.getHandler(), flags);
+ } else {
+ throw new RuntimeException("Not supported in system context");
+ }
+ try {
+ int res = ActivityManagerNative.getDefault().bindService(
+ mMainThread.getApplicationThread(), getActivityToken(),
+ service, service.resolveTypeIfNeeded(getContentResolver()),
+ sd, flags);
+ if (res < 0) {
+ throw new SecurityException(
+ "Not allowed to bind to service " + service);
+ }
+ return res != 0;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public void unbindService(ServiceConnection conn) {
+ if (mPackageInfo != null) {
+ IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
+ getOuterContext(), conn);
+ try {
+ ActivityManagerNative.getDefault().unbindService(sd);
+ } catch (RemoteException e) {
+ }
+ } else {
+ throw new RuntimeException("Not supported in system context");
+ }
+ }
+
+ @Override
+ public boolean startInstrumentation(ComponentName className,
+ String profileFile, Bundle arguments) {
+ try {
+ return ActivityManagerNative.getDefault().startInstrumentation(
+ className, profileFile, 0, arguments, null);
+ } catch (RemoteException e) {
+ // System has crashed, nothing we can do.
+ }
+ return false;
+ }
+
+ @Override
+ public Object getSystemService(String name) {
+ if (WINDOW_SERVICE.equals(name)) {
+ return WindowManagerImpl.getDefault();
+ } else if (LAYOUT_INFLATER_SERVICE.equals(name)) {
+ synchronized (mSync) {
+ LayoutInflater inflater = mLayoutInflater;
+ if (inflater != null) {
+ return inflater;
+ }
+ mLayoutInflater = inflater =
+ PolicyManager.makeNewLayoutInflater(getOuterContext());
+ return inflater;
+ }
+ } else if (ACTIVITY_SERVICE.equals(name)) {
+ return getActivityManager();
+ } else if (INPUT_METHOD_SERVICE.equals(name)) {
+ return InputMethodManager.getInstance(this);
+ } else if (ALARM_SERVICE.equals(name)) {
+ return getAlarmManager();
+ } else if (ACCOUNT_SERVICE.equals(name)) {
+ return getAccountManager();
+ } else if (POWER_SERVICE.equals(name)) {
+ return getPowerManager();
+ } else if (CONNECTIVITY_SERVICE.equals(name)) {
+ return getConnectivityManager();
+ } else if (THROTTLE_SERVICE.equals(name)) {
+ return getThrottleManager();
+ } else if (WIFI_SERVICE.equals(name)) {
+ return getWifiManager();
+ } else if (NOTIFICATION_SERVICE.equals(name)) {
+ return getNotificationManager();
+ } else if (KEYGUARD_SERVICE.equals(name)) {
+ return new KeyguardManager();
+ } else if (ACCESSIBILITY_SERVICE.equals(name)) {
+ return AccessibilityManager.getInstance(this);
+ } else if (LOCATION_SERVICE.equals(name)) {
+ return getLocationManager();
+ } else if (SEARCH_SERVICE.equals(name)) {
+ return getSearchManager();
+ } else if (SENSOR_SERVICE.equals(name)) {
+ return getSensorManager();
+ } else if (STORAGE_SERVICE.equals(name)) {
+ return getStorageManager();
+ } else if (VIBRATOR_SERVICE.equals(name)) {
+ return getVibrator();
+ } else if (STATUS_BAR_SERVICE.equals(name)) {
+ synchronized (mSync) {
+ if (mStatusBarManager == null) {
+ mStatusBarManager = new StatusBarManager(getOuterContext());
+ }
+ return mStatusBarManager;
+ }
+ } else if (AUDIO_SERVICE.equals(name)) {
+ return getAudioManager();
+ } else if (TELEPHONY_SERVICE.equals(name)) {
+ return getTelephonyManager();
+ } else if (CLIPBOARD_SERVICE.equals(name)) {
+ return getClipboardManager();
+ } else if (WALLPAPER_SERVICE.equals(name)) {
+ return getWallpaperManager();
+ } else if (DROPBOX_SERVICE.equals(name)) {
+ return getDropBoxManager();
+ } else if (DEVICE_POLICY_SERVICE.equals(name)) {
+ return getDevicePolicyManager();
+ } else if (UI_MODE_SERVICE.equals(name)) {
+ return getUiModeManager();
+ }
+
+ return null;
+ }
+
+ private AccountManager getAccountManager() {
+ synchronized (mSync) {
+ if (mAccountManager == null) {
+ IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
+ IAccountManager service = IAccountManager.Stub.asInterface(b);
+ mAccountManager = new AccountManager(this, service);
+ }
+ return mAccountManager;
+ }
+ }
+
+ private ActivityManager getActivityManager() {
+ synchronized (mSync) {
+ if (mActivityManager == null) {
+ mActivityManager = new ActivityManager(getOuterContext(),
+ mMainThread.getHandler());
+ }
+ }
+ return mActivityManager;
+ }
+
+ private AlarmManager getAlarmManager() {
+ synchronized (sSync) {
+ if (sAlarmManager == null) {
+ IBinder b = ServiceManager.getService(ALARM_SERVICE);
+ IAlarmManager service = IAlarmManager.Stub.asInterface(b);
+ sAlarmManager = new AlarmManager(service);
+ }
+ }
+ return sAlarmManager;
+ }
+
+ private PowerManager getPowerManager() {
+ synchronized (sSync) {
+ if (sPowerManager == null) {
+ IBinder b = ServiceManager.getService(POWER_SERVICE);
+ IPowerManager service = IPowerManager.Stub.asInterface(b);
+ sPowerManager = new PowerManager(service, mMainThread.getHandler());
+ }
+ }
+ return sPowerManager;
+ }
+
+ private ConnectivityManager getConnectivityManager()
+ {
+ synchronized (sSync) {
+ if (sConnectivityManager == null) {
+ IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
+ IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
+ sConnectivityManager = new ConnectivityManager(service);
+ }
+ }
+ return sConnectivityManager;
+ }
+
+ private ThrottleManager getThrottleManager()
+ {
+ synchronized (sSync) {
+ if (sThrottleManager == null) {
+ IBinder b = ServiceManager.getService(THROTTLE_SERVICE);
+ IThrottleManager service = IThrottleManager.Stub.asInterface(b);
+ sThrottleManager = new ThrottleManager(service);
+ }
+ }
+ return sThrottleManager;
+ }
+
+ private WifiManager getWifiManager()
+ {
+ synchronized (sSync) {
+ if (sWifiManager == null) {
+ IBinder b = ServiceManager.getService(WIFI_SERVICE);
+ IWifiManager service = IWifiManager.Stub.asInterface(b);
+ sWifiManager = new WifiManager(service, mMainThread.getHandler());
+ }
+ }
+ return sWifiManager;
+ }
+
+ private NotificationManager getNotificationManager() {
+ synchronized (mSync) {
+ if (mNotificationManager == null) {
+ mNotificationManager = new NotificationManager(
+ new ContextThemeWrapper(getOuterContext(), com.android.internal.R.style.Theme_Dialog),
+ mMainThread.getHandler());
+ }
+ }
+ return mNotificationManager;
+ }
+
+ private WallpaperManager getWallpaperManager() {
+ synchronized (mSync) {
+ if (mWallpaperManager == null) {
+ mWallpaperManager = new WallpaperManager(getOuterContext(),
+ mMainThread.getHandler());
+ }
+ }
+ return mWallpaperManager;
+ }
+
+ private TelephonyManager getTelephonyManager() {
+ synchronized (mSync) {
+ if (mTelephonyManager == null) {
+ mTelephonyManager = new TelephonyManager(getOuterContext());
+ }
+ }
+ return mTelephonyManager;
+ }
+
+ private ClipboardManager getClipboardManager() {
+ synchronized (mSync) {
+ if (mClipboardManager == null) {
+ mClipboardManager = new ClipboardManager(getOuterContext(),
+ mMainThread.getHandler());
+ }
+ }
+ return mClipboardManager;
+ }
+
+ private LocationManager getLocationManager() {
+ synchronized (sSync) {
+ if (sLocationManager == null) {
+ IBinder b = ServiceManager.getService(LOCATION_SERVICE);
+ ILocationManager service = ILocationManager.Stub.asInterface(b);
+ sLocationManager = new LocationManager(service);
+ }
+ }
+ return sLocationManager;
+ }
+
+ private SearchManager getSearchManager() {
+ synchronized (mSync) {
+ if (mSearchManager == null) {
+ mSearchManager = new SearchManager(getOuterContext(), mMainThread.getHandler());
+ }
+ }
+ return mSearchManager;
+ }
+
+ private SensorManager getSensorManager() {
+ synchronized (mSync) {
+ if (mSensorManager == null) {
+ mSensorManager = new SensorManager(mMainThread.getHandler().getLooper());
+ }
+ }
+ return mSensorManager;
+ }
+
+ private StorageManager getStorageManager() {
+ synchronized (mSync) {
+ if (mStorageManager == null) {
+ try {
+ mStorageManager = new StorageManager(mMainThread.getHandler().getLooper());
+ } catch (RemoteException rex) {
+ Log.e(TAG, "Failed to create StorageManager", rex);
+ mStorageManager = null;
+ }
+ }
+ }
+ return mStorageManager;
+ }
+
+ private Vibrator getVibrator() {
+ synchronized (mSync) {
+ if (mVibrator == null) {
+ mVibrator = new Vibrator();
+ }
+ }
+ return mVibrator;
+ }
+
+ private AudioManager getAudioManager()
+ {
+ if (mAudioManager == null) {
+ mAudioManager = new AudioManager(this);
+ }
+ return mAudioManager;
+ }
+
+ private DropBoxManager getDropBoxManager() {
+ synchronized (mSync) {
+ if (mDropBoxManager == null) {
+ IBinder b = ServiceManager.getService(DROPBOX_SERVICE);
+ IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
+ mDropBoxManager = new DropBoxManager(service);
+ }
+ }
+ return mDropBoxManager;
+ }
+
+ private DevicePolicyManager getDevicePolicyManager() {
+ synchronized (mSync) {
+ if (mDevicePolicyManager == null) {
+ mDevicePolicyManager = DevicePolicyManager.create(this,
+ mMainThread.getHandler());
+ }
+ }
+ return mDevicePolicyManager;
+ }
+
+ private UiModeManager getUiModeManager() {
+ synchronized (mSync) {
+ if (mUiModeManager == null) {
+ mUiModeManager = new UiModeManager();
+ }
+ }
+ return mUiModeManager;
+ }
+
+ @Override
+ public int checkPermission(String permission, int pid, int uid) {
+ if (permission == null) {
+ throw new IllegalArgumentException("permission is null");
+ }
+
+ if (!Process.supportsProcesses()) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+ try {
+ return ActivityManagerNative.getDefault().checkPermission(
+ permission, pid, uid);
+ } catch (RemoteException e) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+ }
+
+ @Override
+ public int checkCallingPermission(String permission) {
+ if (permission == null) {
+ throw new IllegalArgumentException("permission is null");
+ }
+
+ if (!Process.supportsProcesses()) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+ int pid = Binder.getCallingPid();
+ if (pid != Process.myPid()) {
+ return checkPermission(permission, pid,
+ Binder.getCallingUid());
+ }
+ return PackageManager.PERMISSION_DENIED;
+ }
+
+ @Override
+ public int checkCallingOrSelfPermission(String permission) {
+ if (permission == null) {
+ throw new IllegalArgumentException("permission is null");
+ }
+
+ return checkPermission(permission, Binder.getCallingPid(),
+ Binder.getCallingUid());
+ }
+
+ private void enforce(
+ String permission, int resultOfCheck,
+ boolean selfToo, int uid, String message) {
+ if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ (message != null ? (message + ": ") : "") +
+ (selfToo
+ ? "Neither user " + uid + " nor current process has "
+ : "User " + uid + " does not have ") +
+ permission +
+ ".");
+ }
+ }
+
+ public void enforcePermission(
+ String permission, int pid, int uid, String message) {
+ enforce(permission,
+ checkPermission(permission, pid, uid),
+ false,
+ uid,
+ message);
+ }
+
+ public void enforceCallingPermission(String permission, String message) {
+ enforce(permission,
+ checkCallingPermission(permission),
+ false,
+ Binder.getCallingUid(),
+ message);
+ }
+
+ public void enforceCallingOrSelfPermission(
+ String permission, String message) {
+ enforce(permission,
+ checkCallingOrSelfPermission(permission),
+ true,
+ Binder.getCallingUid(),
+ message);
+ }
+
+ @Override
+ public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
+ try {
+ ActivityManagerNative.getDefault().grantUriPermission(
+ mMainThread.getApplicationThread(), toPackage, uri,
+ modeFlags);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void revokeUriPermission(Uri uri, int modeFlags) {
+ try {
+ ActivityManagerNative.getDefault().revokeUriPermission(
+ mMainThread.getApplicationThread(), uri,
+ modeFlags);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
+ if (!Process.supportsProcesses()) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+ try {
+ return ActivityManagerNative.getDefault().checkUriPermission(
+ uri, pid, uid, modeFlags);
+ } catch (RemoteException e) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+ }
+
+ @Override
+ public int checkCallingUriPermission(Uri uri, int modeFlags) {
+ if (!Process.supportsProcesses()) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+ int pid = Binder.getCallingPid();
+ if (pid != Process.myPid()) {
+ return checkUriPermission(uri, pid,
+ Binder.getCallingUid(), modeFlags);
+ }
+ return PackageManager.PERMISSION_DENIED;
+ }
+
+ @Override
+ public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) {
+ return checkUriPermission(uri, Binder.getCallingPid(),
+ Binder.getCallingUid(), modeFlags);
+ }
+
+ @Override
+ public int checkUriPermission(Uri uri, String readPermission,
+ String writePermission, int pid, int uid, int modeFlags) {
+ if (DEBUG) {
+ Log.i("foo", "checkUriPermission: uri=" + uri + "readPermission="
+ + readPermission + " writePermission=" + writePermission
+ + " pid=" + pid + " uid=" + uid + " mode" + modeFlags);
+ }
+ if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+ if (readPermission == null
+ || checkPermission(readPermission, pid, uid)
+ == PackageManager.PERMISSION_GRANTED) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+ }
+ if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ if (writePermission == null
+ || checkPermission(writePermission, pid, uid)
+ == PackageManager.PERMISSION_GRANTED) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+ }
+ return uri != null ? checkUriPermission(uri, pid, uid, modeFlags)
+ : PackageManager.PERMISSION_DENIED;
+ }
+
+ private String uriModeFlagToString(int uriModeFlags) {
+ switch (uriModeFlags) {
+ case Intent.FLAG_GRANT_READ_URI_PERMISSION |
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
+ return "read and write";
+ case Intent.FLAG_GRANT_READ_URI_PERMISSION:
+ return "read";
+ case Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
+ return "write";
+ }
+ throw new IllegalArgumentException(
+ "Unknown permission mode flags: " + uriModeFlags);
+ }
+
+ private void enforceForUri(
+ int modeFlags, int resultOfCheck, boolean selfToo,
+ int uid, Uri uri, String message) {
+ if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ (message != null ? (message + ": ") : "") +
+ (selfToo
+ ? "Neither user " + uid + " nor current process has "
+ : "User " + uid + " does not have ") +
+ uriModeFlagToString(modeFlags) +
+ " permission on " +
+ uri +
+ ".");
+ }
+ }
+
+ public void enforceUriPermission(
+ Uri uri, int pid, int uid, int modeFlags, String message) {
+ enforceForUri(
+ modeFlags, checkUriPermission(uri, pid, uid, modeFlags),
+ false, uid, uri, message);
+ }
+
+ public void enforceCallingUriPermission(
+ Uri uri, int modeFlags, String message) {
+ enforceForUri(
+ modeFlags, checkCallingUriPermission(uri, modeFlags),
+ false, Binder.getCallingUid(), uri, message);
+ }
+
+ public void enforceCallingOrSelfUriPermission(
+ Uri uri, int modeFlags, String message) {
+ enforceForUri(
+ modeFlags,
+ checkCallingOrSelfUriPermission(uri, modeFlags), true,
+ Binder.getCallingUid(), uri, message);
+ }
+
+ public void enforceUriPermission(
+ Uri uri, String readPermission, String writePermission,
+ int pid, int uid, int modeFlags, String message) {
+ enforceForUri(modeFlags,
+ checkUriPermission(
+ uri, readPermission, writePermission, pid, uid,
+ modeFlags),
+ false,
+ uid,
+ uri,
+ message);
+ }
+
+ @Override
+ public Context createPackageContext(String packageName, int flags)
+ throws PackageManager.NameNotFoundException {
+ if (packageName.equals("system") || packageName.equals("android")) {
+ return new ContextImpl(mMainThread.getSystemContext());
+ }
+
+ ActivityThread.PackageInfo pi =
+ mMainThread.getPackageInfo(packageName, flags);
+ if (pi != null) {
+ ContextImpl c = new ContextImpl();
+ c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
+ c.init(pi, null, mMainThread, mResources);
+ if (c.mResources != null) {
+ return c;
+ }
+ }
+
+ // Should be a better exception.
+ throw new PackageManager.NameNotFoundException(
+ "Application package " + packageName + " not found");
+ }
+
+ @Override
+ public boolean isRestricted() {
+ return mRestricted;
+ }
+
+ private File getDataDirFile() {
+ if (mPackageInfo != null) {
+ return mPackageInfo.getDataDirFile();
+ }
+ throw new RuntimeException("Not supported in system context");
+ }
+
+ @Override
+ public File getDir(String name, int mode) {
+ name = "app_" + name;
+ File file = makeFilename(getDataDirFile(), name);
+ if (!file.exists()) {
+ file.mkdir();
+ setFilePermissionsFromMode(file.getPath(), mode,
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH);
+ }
+ return file;
+ }
+
+ static ContextImpl createSystemContext(ActivityThread mainThread) {
+ ContextImpl context = new ContextImpl();
+ context.init(Resources.getSystem(), mainThread);
+ return context;
+ }
+
+ ContextImpl() {
+ // For debug only
+ //++sInstanceCount;
+ mOuterContext = this;
+ }
+
+ /**
+ * Create a new ApplicationContext from an existing one. The new one
+ * works and operates the same as the one it is copying.
+ *
+ * @param context Existing application context.
+ */
+ public ContextImpl(ContextImpl context) {
+ ++sInstanceCount;
+ mPackageInfo = context.mPackageInfo;
+ mResources = context.mResources;
+ mMainThread = context.mMainThread;
+ mContentResolver = context.mContentResolver;
+ mOuterContext = this;
+ }
+
+ final void init(ActivityThread.PackageInfo packageInfo,
+ IBinder activityToken, ActivityThread mainThread) {
+ init(packageInfo, activityToken, mainThread, null);
+ }
+
+ final void init(ActivityThread.PackageInfo packageInfo,
+ IBinder activityToken, ActivityThread mainThread,
+ Resources container) {
+ mPackageInfo = packageInfo;
+ mResources = mPackageInfo.getResources(mainThread);
+
+ if (mResources != null && container != null
+ && container.getCompatibilityInfo().applicationScale !=
+ mResources.getCompatibilityInfo().applicationScale) {
+ if (DEBUG) {
+ Log.d(TAG, "loaded context has different scaling. Using container's" +
+ " compatiblity info:" + container.getDisplayMetrics());
+ }
+ mResources = mainThread.getTopLevelResources(
+ mPackageInfo.getResDir(), container.getCompatibilityInfo().copy());
+ }
+ mMainThread = mainThread;
+ mContentResolver = new ApplicationContentResolver(this, mainThread);
+
+ setActivityToken(activityToken);
+ }
+
+ final void init(Resources resources, ActivityThread mainThread) {
+ mPackageInfo = null;
+ mResources = resources;
+ mMainThread = mainThread;
+ mContentResolver = new ApplicationContentResolver(this, mainThread);
+ }
+
+ final void scheduleFinalCleanup(String who, String what) {
+ mMainThread.scheduleContextCleanup(this, who, what);
+ }
+
+ final void performFinalCleanup(String who, String what) {
+ //Log.i(TAG, "Cleanup up context: " + this);
+ mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
+ }
+
+ final Context getReceiverRestrictedContext() {
+ if (mReceiverRestrictedContext != null) {
+ return mReceiverRestrictedContext;
+ }
+ return mReceiverRestrictedContext = new ReceiverRestrictedContext(getOuterContext());
+ }
+
+ final void setActivityToken(IBinder token) {
+ mActivityToken = token;
+ }
+
+ final void setOuterContext(Context context) {
+ mOuterContext = context;
+ }
+
+ final Context getOuterContext() {
+ return mOuterContext;
+ }
+
+ final IBinder getActivityToken() {
+ return mActivityToken;
+ }
+
+ private static void setFilePermissionsFromMode(String name, int mode,
+ int extraPermissions) {
+ int perms = FileUtils.S_IRUSR|FileUtils.S_IWUSR
+ |FileUtils.S_IRGRP|FileUtils.S_IWGRP
+ |extraPermissions;
+ if ((mode&MODE_WORLD_READABLE) != 0) {
+ perms |= FileUtils.S_IROTH;
+ }
+ if ((mode&MODE_WORLD_WRITEABLE) != 0) {
+ perms |= FileUtils.S_IWOTH;
+ }
+ if (DEBUG) {
+ Log.i(TAG, "File " + name + ": mode=0x" + Integer.toHexString(mode)
+ + ", perms=0x" + Integer.toHexString(perms));
+ }
+ FileUtils.setPermissions(name, perms, -1, -1);
+ }
+
+ private File validateFilePath(String name, boolean createDirectory) {
+ File dir;
+ File f;
+
+ if (name.charAt(0) == File.separatorChar) {
+ String dirPath = name.substring(0, name.lastIndexOf(File.separatorChar));
+ dir = new File(dirPath);
+ name = name.substring(name.lastIndexOf(File.separatorChar));
+ f = new File(dir, name);
+ } else {
+ dir = getDatabasesDir();
+ f = makeFilename(dir, name);
+ }
+
+ if (createDirectory && !dir.isDirectory() && dir.mkdir()) {
+ FileUtils.setPermissions(dir.getPath(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+ -1, -1);
+ }
+
+ return f;
+ }
+
+ private File makeFilename(File base, String name) {
+ if (name.indexOf(File.separatorChar) < 0) {
+ return new File(base, name);
+ }
+ throw new IllegalArgumentException(
+ "File " + name + " contains a path separator");
+ }
+
+ // ----------------------------------------------------------------------
+ // ----------------------------------------------------------------------
+ // ----------------------------------------------------------------------
+
+ private static final class ApplicationContentResolver extends ContentResolver {
+ public ApplicationContentResolver(Context context,
+ ActivityThread mainThread)
+ {
+ super(context);
+ mMainThread = mainThread;
+ }
+
+ @Override
+ protected IContentProvider acquireProvider(Context context, String name)
+ {
+ return mMainThread.acquireProvider(context, name);
+ }
+
+ @Override
+ public boolean releaseProvider(IContentProvider provider)
+ {
+ return mMainThread.releaseProvider(provider);
+ }
+
+ private final ActivityThread mMainThread;
+ }
+
+ // ----------------------------------------------------------------------
+ // ----------------------------------------------------------------------
+ // ----------------------------------------------------------------------
+
+ /*package*/
+ static final class ApplicationPackageManager extends PackageManager {
+ @Override
+ public PackageInfo getPackageInfo(String packageName, int flags)
+ throws NameNotFoundException {
+ try {
+ PackageInfo pi = mPM.getPackageInfo(packageName, flags);
+ if (pi != null) {
+ return pi;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+
+ throw new NameNotFoundException(packageName);
+ }
+
+ @Override
+ public String[] currentToCanonicalPackageNames(String[] names) {
+ try {
+ return mPM.currentToCanonicalPackageNames(names);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public String[] canonicalToCurrentPackageNames(String[] names) {
+ try {
+ return mPM.canonicalToCurrentPackageNames(names);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public Intent getLaunchIntentForPackage(String packageName) {
+ // First see if the package has an INFO activity; the existence of
+ // such an activity is implied to be the desired front-door for the
+ // overall package (such as if it has multiple launcher entries).
+ Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+ intentToResolve.addCategory(Intent.CATEGORY_INFO);
+ intentToResolve.setPackage(packageName);
+ ResolveInfo resolveInfo = resolveActivity(intentToResolve, 0);
+
+ // Otherwise, try to find a main launcher activity.
+ if (resolveInfo == null) {
+ // reuse the intent instance
+ intentToResolve.removeCategory(Intent.CATEGORY_INFO);
+ intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
+ intentToResolve.setPackage(packageName);
+ resolveInfo = resolveActivity(intentToResolve, 0);
+ }
+ if (resolveInfo == null) {
+ return null;
+ }
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClassName(packageName, resolveInfo.activityInfo.name);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return intent;
+ }
+
+ @Override
+ public int[] getPackageGids(String packageName)
+ throws NameNotFoundException {
+ try {
+ int[] gids = mPM.getPackageGids(packageName);
+ if (gids == null || gids.length > 0) {
+ return gids;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+
+ throw new NameNotFoundException(packageName);
+ }
+
+ @Override
+ public PermissionInfo getPermissionInfo(String name, int flags)
+ throws NameNotFoundException {
+ try {
+ PermissionInfo pi = mPM.getPermissionInfo(name, flags);
+ if (pi != null) {
+ return pi;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+
+ throw new NameNotFoundException(name);
+ }
+
+ @Override
+ public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
+ throws NameNotFoundException {
+ try {
+ List<PermissionInfo> pi = mPM.queryPermissionsByGroup(group, flags);
+ if (pi != null) {
+ return pi;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+
+ throw new NameNotFoundException(group);
+ }
+
+ @Override
+ public PermissionGroupInfo getPermissionGroupInfo(String name,
+ int flags) throws NameNotFoundException {
+ try {
+ PermissionGroupInfo pgi = mPM.getPermissionGroupInfo(name, flags);
+ if (pgi != null) {
+ return pgi;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+
+ throw new NameNotFoundException(name);
+ }
+
+ @Override
+ public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
+ try {
+ return mPM.getAllPermissionGroups(flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public ApplicationInfo getApplicationInfo(String packageName, int flags)
+ throws NameNotFoundException {
+ try {
+ ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags);
+ if (ai != null) {
+ return ai;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+
+ throw new NameNotFoundException(packageName);
+ }
+
+ @Override
+ public ActivityInfo getActivityInfo(ComponentName className, int flags)
+ throws NameNotFoundException {
+ try {
+ ActivityInfo ai = mPM.getActivityInfo(className, flags);
+ if (ai != null) {
+ return ai;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+
+ throw new NameNotFoundException(className.toString());
+ }
+
+ @Override
+ public ActivityInfo getReceiverInfo(ComponentName className, int flags)
+ throws NameNotFoundException {
+ try {
+ ActivityInfo ai = mPM.getReceiverInfo(className, flags);
+ if (ai != null) {
+ return ai;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+
+ throw new NameNotFoundException(className.toString());
+ }
+
+ @Override
+ public ServiceInfo getServiceInfo(ComponentName className, int flags)
+ throws NameNotFoundException {
+ try {
+ ServiceInfo si = mPM.getServiceInfo(className, flags);
+ if (si != null) {
+ return si;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+
+ throw new NameNotFoundException(className.toString());
+ }
+
+ @Override
+ public String[] getSystemSharedLibraryNames() {
+ try {
+ return mPM.getSystemSharedLibraryNames();
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public FeatureInfo[] getSystemAvailableFeatures() {
+ try {
+ return mPM.getSystemAvailableFeatures();
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public boolean hasSystemFeature(String name) {
+ try {
+ return mPM.hasSystemFeature(name);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public int checkPermission(String permName, String pkgName) {
+ try {
+ return mPM.checkPermission(permName, pkgName);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public boolean addPermission(PermissionInfo info) {
+ try {
+ return mPM.addPermission(info);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public boolean addPermissionAsync(PermissionInfo info) {
+ try {
+ return mPM.addPermissionAsync(info);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public void removePermission(String name) {
+ try {
+ mPM.removePermission(name);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public int checkSignatures(String pkg1, String pkg2) {
+ try {
+ return mPM.checkSignatures(pkg1, pkg2);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public int checkSignatures(int uid1, int uid2) {
+ try {
+ return mPM.checkUidSignatures(uid1, uid2);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public String[] getPackagesForUid(int uid) {
+ try {
+ return mPM.getPackagesForUid(uid);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public String getNameForUid(int uid) {
+ try {
+ return mPM.getNameForUid(uid);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public int getUidForSharedUser(String sharedUserName)
+ throws NameNotFoundException {
+ try {
+ int uid = mPM.getUidForSharedUser(sharedUserName);
+ if(uid != -1) {
+ return uid;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
+ }
+
+ @Override
+ public List<PackageInfo> getInstalledPackages(int flags) {
+ try {
+ return mPM.getInstalledPackages(flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public List<ApplicationInfo> getInstalledApplications(int flags) {
+ try {
+ return mPM.getInstalledApplications(flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public ResolveInfo resolveActivity(Intent intent, int flags) {
+ try {
+ return mPM.resolveIntent(
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public List<ResolveInfo> queryIntentActivities(Intent intent,
+ int flags) {
+ try {
+ return mPM.queryIntentActivities(
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public List<ResolveInfo> queryIntentActivityOptions(
+ ComponentName caller, Intent[] specifics, Intent intent,
+ int flags) {
+ final ContentResolver resolver = mContext.getContentResolver();
+
+ String[] specificTypes = null;
+ if (specifics != null) {
+ final int N = specifics.length;
+ for (int i=0; i<N; i++) {
+ Intent sp = specifics[i];
+ if (sp != null) {
+ String t = sp.resolveTypeIfNeeded(resolver);
+ if (t != null) {
+ if (specificTypes == null) {
+ specificTypes = new String[N];
+ }
+ specificTypes[i] = t;
+ }
+ }
+ }
+ }
+
+ try {
+ return mPM.queryIntentActivityOptions(caller, specifics,
+ specificTypes, intent, intent.resolveTypeIfNeeded(resolver),
+ flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
+ try {
+ return mPM.queryIntentReceivers(
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public ResolveInfo resolveService(Intent intent, int flags) {
+ try {
+ return mPM.resolveService(
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
+ try {
+ return mPM.queryIntentServices(
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public ProviderInfo resolveContentProvider(String name,
+ int flags) {
+ try {
+ return mPM.resolveContentProvider(name, flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public List<ProviderInfo> queryContentProviders(String processName,
+ int uid, int flags) {
+ try {
+ return mPM.queryContentProviders(processName, uid, flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public InstrumentationInfo getInstrumentationInfo(
+ ComponentName className, int flags)
+ throws NameNotFoundException {
+ try {
+ InstrumentationInfo ii = mPM.getInstrumentationInfo(
+ className, flags);
+ if (ii != null) {
+ return ii;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+
+ throw new NameNotFoundException(className.toString());
+ }
+
+ @Override
+ public List<InstrumentationInfo> queryInstrumentation(
+ String targetPackage, int flags) {
+ try {
+ return mPM.queryInstrumentation(targetPackage, flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override public Drawable getDrawable(String packageName, int resid,
+ ApplicationInfo appInfo) {
+ ResourceName name = new ResourceName(packageName, resid);
+ Drawable dr = getCachedIcon(name);
+ if (dr != null) {
+ return dr;
+ }
+ if (appInfo == null) {
+ try {
+ appInfo = getApplicationInfo(packageName, 0);
+ } catch (NameNotFoundException e) {
+ return null;
+ }
+ }
+ try {
+ Resources r = getResourcesForApplication(appInfo);
+ dr = r.getDrawable(resid);
+ if (false) {
+ RuntimeException e = new RuntimeException("here");
+ e.fillInStackTrace();
+ Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resid)
+ + " from package " + packageName
+ + ": app scale=" + r.getCompatibilityInfo().applicationScale
+ + ", caller scale=" + mContext.getResources().getCompatibilityInfo().applicationScale,
+ e);
+ }
+ if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x"
+ + Integer.toHexString(resid) + " from " + r
+ + ": " + dr);
+ putCachedIcon(name, dr);
+ return dr;
+ } catch (NameNotFoundException e) {
+ Log.w("PackageManager", "Failure retrieving resources for"
+ + appInfo.packageName);
+ } catch (RuntimeException e) {
+ // If an exception was thrown, fall through to return
+ // default icon.
+ Log.w("PackageManager", "Failure retrieving icon 0x"
+ + Integer.toHexString(resid) + " in package "
+ + packageName, e);
+ }
+ return null;
+ }
+
+ @Override public Drawable getActivityIcon(ComponentName activityName)
+ throws NameNotFoundException {
+ return getActivityInfo(activityName, 0).loadIcon(this);
+ }
+
+ @Override public Drawable getActivityIcon(Intent intent)
+ throws NameNotFoundException {
+ if (intent.getComponent() != null) {
+ return getActivityIcon(intent.getComponent());
+ }
+
+ ResolveInfo info = resolveActivity(
+ intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if (info != null) {
+ return info.activityInfo.loadIcon(this);
+ }
+
+ throw new NameNotFoundException(intent.toURI());
+ }
+
+ @Override public Drawable getDefaultActivityIcon() {
+ return Resources.getSystem().getDrawable(
+ com.android.internal.R.drawable.sym_def_app_icon);
+ }
+
+ @Override public Drawable getApplicationIcon(ApplicationInfo info) {
+ return info.loadIcon(this);
+ }
+
+ @Override public Drawable getApplicationIcon(String packageName)
+ throws NameNotFoundException {
+ return getApplicationIcon(getApplicationInfo(packageName, 0));
+ }
+
+ @Override public Resources getResourcesForActivity(
+ ComponentName activityName) throws NameNotFoundException {
+ return getResourcesForApplication(
+ getActivityInfo(activityName, 0).applicationInfo);
+ }
+
+ @Override public Resources getResourcesForApplication(
+ ApplicationInfo app) throws NameNotFoundException {
+ if (app.packageName.equals("system")) {
+ return mContext.mMainThread.getSystemContext().getResources();
+ }
+ Resources r = mContext.mMainThread.getTopLevelResources(
+ app.uid == Process.myUid() ? app.sourceDir
+ : app.publicSourceDir, mContext.mPackageInfo);
+ if (r != null) {
+ return r;
+ }
+ throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
+ }
+
+ @Override public Resources getResourcesForApplication(
+ String appPackageName) throws NameNotFoundException {
+ return getResourcesForApplication(
+ getApplicationInfo(appPackageName, 0));
+ }
+
+ int mCachedSafeMode = -1;
+ @Override public boolean isSafeMode() {
+ try {
+ if (mCachedSafeMode < 0) {
+ mCachedSafeMode = mPM.isSafeMode() ? 1 : 0;
+ }
+ return mCachedSafeMode != 0;
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ static void configurationChanged() {
+ synchronized (sSync) {
+ sIconCache.clear();
+ sStringCache.clear();
+ }
+ }
+
+ ApplicationPackageManager(ContextImpl context,
+ IPackageManager pm) {
+ mContext = context;
+ mPM = pm;
+ }
+
+ private Drawable getCachedIcon(ResourceName name) {
+ synchronized (sSync) {
+ WeakReference<Drawable> wr = sIconCache.get(name);
+ if (DEBUG_ICONS) Log.v(TAG, "Get cached weak drawable ref for "
+ + name + ": " + wr);
+ if (wr != null) { // we have the activity
+ Drawable dr = wr.get();
+ if (dr != null) {
+ if (DEBUG_ICONS) Log.v(TAG, "Get cached drawable for "
+ + name + ": " + dr);
+ return dr;
+ }
+ // our entry has been purged
+ sIconCache.remove(name);
+ }
+ }
+ return null;
+ }
+
+ private void putCachedIcon(ResourceName name, Drawable dr) {
+ synchronized (sSync) {
+ sIconCache.put(name, new WeakReference<Drawable>(dr));
+ if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for "
+ + name + ": " + dr);
+ }
+ }
+
+ static final void handlePackageBroadcast(int cmd, String[] pkgList,
+ boolean hasPkgInfo) {
+ boolean immediateGc = false;
+ if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) {
+ immediateGc = true;
+ }
+ if (pkgList != null && (pkgList.length > 0)) {
+ boolean needCleanup = false;
+ for (String ssp : pkgList) {
+ synchronized (sSync) {
+ if (sIconCache.size() > 0) {
+ Iterator<ResourceName> it = sIconCache.keySet().iterator();
+ while (it.hasNext()) {
+ ResourceName nm = it.next();
+ if (nm.packageName.equals(ssp)) {
+ //Log.i(TAG, "Removing cached drawable for " + nm);
+ it.remove();
+ needCleanup = true;
+ }
+ }
+ }
+ if (sStringCache.size() > 0) {
+ Iterator<ResourceName> it = sStringCache.keySet().iterator();
+ while (it.hasNext()) {
+ ResourceName nm = it.next();
+ if (nm.packageName.equals(ssp)) {
+ //Log.i(TAG, "Removing cached string for " + nm);
+ it.remove();
+ needCleanup = true;
+ }
+ }
+ }
+ }
+ }
+ if (needCleanup || hasPkgInfo) {
+ if (immediateGc) {
+ // Schedule an immediate gc.
+ Runtime.getRuntime().gc();
+ } else {
+ ActivityThread.currentActivityThread().scheduleGcIdler();
+ }
+ }
+ }
+ }
+
+ private static final class ResourceName {
+ final String packageName;
+ final int iconId;
+
+ ResourceName(String _packageName, int _iconId) {
+ packageName = _packageName;
+ iconId = _iconId;
+ }
+
+ ResourceName(ApplicationInfo aInfo, int _iconId) {
+ this(aInfo.packageName, _iconId);
+ }
+
+ ResourceName(ComponentInfo cInfo, int _iconId) {
+ this(cInfo.applicationInfo.packageName, _iconId);
+ }
+
+ ResourceName(ResolveInfo rInfo, int _iconId) {
+ this(rInfo.activityInfo.applicationInfo.packageName, _iconId);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ResourceName that = (ResourceName) o;
+
+ if (iconId != that.iconId) return false;
+ return !(packageName != null ?
+ !packageName.equals(that.packageName) : that.packageName != null);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result;
+ result = packageName.hashCode();
+ result = 31 * result + iconId;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "{ResourceName " + packageName + " / " + iconId + "}";
+ }
+ }
+
+ private CharSequence getCachedString(ResourceName name) {
+ synchronized (sSync) {
+ WeakReference<CharSequence> wr = sStringCache.get(name);
+ if (wr != null) { // we have the activity
+ CharSequence cs = wr.get();
+ if (cs != null) {
+ return cs;
+ }
+ // our entry has been purged
+ sStringCache.remove(name);
+ }
+ }
+ return null;
+ }
+
+ private void putCachedString(ResourceName name, CharSequence cs) {
+ synchronized (sSync) {
+ sStringCache.put(name, new WeakReference<CharSequence>(cs));
+ }
+ }
+
+ @Override
+ public CharSequence getText(String packageName, int resid,
+ ApplicationInfo appInfo) {
+ ResourceName name = new ResourceName(packageName, resid);
+ CharSequence text = getCachedString(name);
+ if (text != null) {
+ return text;
+ }
+ if (appInfo == null) {
+ try {
+ appInfo = getApplicationInfo(packageName, 0);
+ } catch (NameNotFoundException e) {
+ return null;
+ }
+ }
+ try {
+ Resources r = getResourcesForApplication(appInfo);
+ text = r.getText(resid);
+ putCachedString(name, text);
+ return text;
+ } catch (NameNotFoundException e) {
+ Log.w("PackageManager", "Failure retrieving resources for"
+ + appInfo.packageName);
+ } catch (RuntimeException e) {
+ // If an exception was thrown, fall through to return
+ // default icon.
+ Log.w("PackageManager", "Failure retrieving text 0x"
+ + Integer.toHexString(resid) + " in package "
+ + packageName, e);
+ }
+ return null;
+ }
+
+ @Override
+ public XmlResourceParser getXml(String packageName, int resid,
+ ApplicationInfo appInfo) {
+ if (appInfo == null) {
+ try {
+ appInfo = getApplicationInfo(packageName, 0);
+ } catch (NameNotFoundException e) {
+ return null;
+ }
+ }
+ try {
+ Resources r = getResourcesForApplication(appInfo);
+ return r.getXml(resid);
+ } catch (RuntimeException e) {
+ // If an exception was thrown, fall through to return
+ // default icon.
+ Log.w("PackageManager", "Failure retrieving xml 0x"
+ + Integer.toHexString(resid) + " in package "
+ + packageName, e);
+ } catch (NameNotFoundException e) {
+ Log.w("PackageManager", "Failure retrieving resources for"
+ + appInfo.packageName);
+ }
+ return null;
+ }
+
+ @Override
+ public CharSequence getApplicationLabel(ApplicationInfo info) {
+ return info.loadLabel(this);
+ }
+
+ @Override
+ public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
+ String installerPackageName) {
+ try {
+ mPM.installPackage(packageURI, observer, flags, installerPackageName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
+ try {
+ mPM.movePackage(packageName, observer, flags);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public String getInstallerPackageName(String packageName) {
+ try {
+ return mPM.getInstallerPackageName(packageName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ return null;
+ }
+
+ @Override
+ public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
+ try {
+ mPM.deletePackage(packageName, observer, flags);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+ @Override
+ public void clearApplicationUserData(String packageName,
+ IPackageDataObserver observer) {
+ try {
+ mPM.clearApplicationUserData(packageName, observer);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+ @Override
+ public void deleteApplicationCacheFiles(String packageName,
+ IPackageDataObserver observer) {
+ try {
+ mPM.deleteApplicationCacheFiles(packageName, observer);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+ @Override
+ public void freeStorageAndNotify(long idealStorageSize, IPackageDataObserver observer) {
+ try {
+ mPM.freeStorageAndNotify(idealStorageSize, observer);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public void freeStorage(long freeStorageSize, IntentSender pi) {
+ try {
+ mPM.freeStorage(freeStorageSize, pi);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public void getPackageSizeInfo(String packageName,
+ IPackageStatsObserver observer) {
+ try {
+ mPM.getPackageSizeInfo(packageName, observer);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+ @Override
+ public void addPackageToPreferred(String packageName) {
+ try {
+ mPM.addPackageToPreferred(packageName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public void removePackageFromPreferred(String packageName) {
+ try {
+ mPM.removePackageFromPreferred(packageName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public List<PackageInfo> getPreferredPackages(int flags) {
+ try {
+ return mPM.getPreferredPackages(flags);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ return new ArrayList<PackageInfo>();
+ }
+
+ @Override
+ public void addPreferredActivity(IntentFilter filter,
+ int match, ComponentName[] set, ComponentName activity) {
+ try {
+ mPM.addPreferredActivity(filter, match, set, activity);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public void replacePreferredActivity(IntentFilter filter,
+ int match, ComponentName[] set, ComponentName activity) {
+ try {
+ mPM.replacePreferredActivity(filter, match, set, activity);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public void clearPackagePreferredActivities(String packageName) {
+ try {
+ mPM.clearPackagePreferredActivities(packageName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public int getPreferredActivities(List<IntentFilter> outFilters,
+ List<ComponentName> outActivities, String packageName) {
+ try {
+ return mPM.getPreferredActivities(outFilters, outActivities, packageName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ return 0;
+ }
+
+ @Override
+ public void setComponentEnabledSetting(ComponentName componentName,
+ int newState, int flags) {
+ try {
+ mPM.setComponentEnabledSetting(componentName, newState, flags);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public int getComponentEnabledSetting(ComponentName componentName) {
+ try {
+ return mPM.getComponentEnabledSetting(componentName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+ }
+
+ @Override
+ public void setApplicationEnabledSetting(String packageName,
+ int newState, int flags) {
+ try {
+ mPM.setApplicationEnabledSetting(packageName, newState, flags);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public int getApplicationEnabledSetting(String packageName) {
+ try {
+ return mPM.getApplicationEnabledSetting(packageName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+ }
+
+ private final ContextImpl mContext;
+ private final IPackageManager mPM;
+
+ private static final Object sSync = new Object();
+ private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache
+ = new HashMap<ResourceName, WeakReference<Drawable> >();
+ private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache
+ = new HashMap<ResourceName, WeakReference<CharSequence> >();
+ }
+
+ // ----------------------------------------------------------------------
+ // ----------------------------------------------------------------------
+ // ----------------------------------------------------------------------
+
+ private static final class SharedPreferencesImpl implements SharedPreferences {
+
+ private final File mFile;
+ private final File mBackupFile;
+ private final int mMode;
+ private Map mMap;
+ private final FileStatus mFileStatus = new FileStatus();
+ private long mTimestamp;
+
+ private static final Object mContent = new Object();
+ private WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners;
+
+ SharedPreferencesImpl(
+ File file, int mode, Map initialContents) {
+ mFile = file;
+ mBackupFile = makeBackupFile(file);
+ mMode = mode;
+ mMap = initialContents != null ? initialContents : new HashMap();
+ if (FileUtils.getFileStatus(file.getPath(), mFileStatus)) {
+ mTimestamp = mFileStatus.mtime;
+ }
+ mListeners = new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
+ }
+
+ public boolean hasFileChanged() {
+ synchronized (this) {
+ if (!FileUtils.getFileStatus(mFile.getPath(), mFileStatus)) {
+ return true;
+ }
+ return mTimestamp != mFileStatus.mtime;
+ }
+ }
+
+ public void replace(Map newContents) {
+ if (newContents != null) {
+ synchronized (this) {
+ mMap = newContents;
+ }
+ }
+ }
+
+ public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
+ synchronized(this) {
+ mListeners.put(listener, mContent);
+ }
+ }
+
+ public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
+ synchronized(this) {
+ mListeners.remove(listener);
+ }
+ }
+
+ public Map<String, ?> getAll() {
+ synchronized(this) {
+ //noinspection unchecked
+ return new HashMap(mMap);
+ }
+ }
+
+ public String getString(String key, String defValue) {
+ synchronized (this) {
+ String v = (String)mMap.get(key);
+ return v != null ? v : defValue;
+ }
+ }
+
+ public int getInt(String key, int defValue) {
+ synchronized (this) {
+ Integer v = (Integer)mMap.get(key);
+ return v != null ? v : defValue;
+ }
+ }
+ public long getLong(String key, long defValue) {
+ synchronized (this) {
+ Long v = (Long) mMap.get(key);
+ return v != null ? v : defValue;
+ }
+ }
+ public float getFloat(String key, float defValue) {
+ synchronized (this) {
+ Float v = (Float)mMap.get(key);
+ return v != null ? v : defValue;
+ }
+ }
+ public boolean getBoolean(String key, boolean defValue) {
+ synchronized (this) {
+ Boolean v = (Boolean)mMap.get(key);
+ return v != null ? v : defValue;
+ }
+ }
+
+ public boolean contains(String key) {
+ synchronized (this) {
+ return mMap.containsKey(key);
+ }
+ }
+
+ public final class EditorImpl implements Editor {
+ private final Map<String, Object> mModified = Maps.newHashMap();
+ private boolean mClear = false;
+
+ public Editor putString(String key, String value) {
+ synchronized (this) {
+ mModified.put(key, value);
+ return this;
+ }
+ }
+ public Editor putInt(String key, int value) {
+ synchronized (this) {
+ mModified.put(key, value);
+ return this;
+ }
+ }
+ public Editor putLong(String key, long value) {
+ synchronized (this) {
+ mModified.put(key, value);
+ return this;
+ }
+ }
+ public Editor putFloat(String key, float value) {
+ synchronized (this) {
+ mModified.put(key, value);
+ return this;
+ }
+ }
+ public Editor putBoolean(String key, boolean value) {
+ synchronized (this) {
+ mModified.put(key, value);
+ return this;
+ }
+ }
+
+ public Editor remove(String key) {
+ synchronized (this) {
+ mModified.put(key, this);
+ return this;
+ }
+ }
+
+ public Editor clear() {
+ synchronized (this) {
+ mClear = true;
+ return this;
+ }
+ }
+
+ public boolean commit() {
+ boolean returnValue;
+
+ boolean hasListeners;
+ List<String> keysModified = null;
+ Set<OnSharedPreferenceChangeListener> listeners = null;
+
+ synchronized (SharedPreferencesImpl.this) {
+ hasListeners = mListeners.size() > 0;
+ if (hasListeners) {
+ keysModified = new ArrayList<String>();
+ listeners =
+ new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
+ }
+
+ synchronized (this) {
+ if (mClear) {
+ mMap.clear();
+ mClear = false;
+ }
+
+ for (Entry<String, Object> e : mModified.entrySet()) {
+ String k = e.getKey();
+ Object v = e.getValue();
+ if (v == this) {
+ mMap.remove(k);
+ } else {
+ mMap.put(k, v);
+ }
+
+ if (hasListeners) {
+ keysModified.add(k);
+ }
+ }
+
+ mModified.clear();
+ }
+
+ returnValue = writeFileLocked();
+ }
+
+ if (hasListeners) {
+ for (int i = keysModified.size() - 1; i >= 0; i--) {
+ final String key = keysModified.get(i);
+ for (OnSharedPreferenceChangeListener listener : listeners) {
+ if (listener != null) {
+ listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key);
+ }
+ }
+ }
+ }
+
+ return returnValue;
+ }
+ }
+
+ public Editor edit() {
+ return new EditorImpl();
+ }
+
+ private FileOutputStream createFileOutputStream(File file) {
+ FileOutputStream str = null;
+ try {
+ str = new FileOutputStream(file);
+ } catch (FileNotFoundException e) {
+ File parent = file.getParentFile();
+ if (!parent.mkdir()) {
+ Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file);
+ return null;
+ }
+ FileUtils.setPermissions(
+ parent.getPath(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+ -1, -1);
+ try {
+ str = new FileOutputStream(file);
+ } catch (FileNotFoundException e2) {
+ Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2);
+ }
+ }
+ return str;
+ }
+
+ private boolean writeFileLocked() {
+ // Rename the current file so it may be used as a backup during the next read
+ if (mFile.exists()) {
+ if (!mBackupFile.exists()) {
+ if (!mFile.renameTo(mBackupFile)) {
+ Log.e(TAG, "Couldn't rename file " + mFile
+ + " to backup file " + mBackupFile);
+ return false;
+ }
+ } else {
+ mFile.delete();
+ }
+ }
+
+ // Attempt to write the file, delete the backup and return true as atomically as
+ // possible. If any exception occurs, delete the new file; next time we will restore
+ // from the backup.
+ try {
+ FileOutputStream str = createFileOutputStream(mFile);
+ if (str == null) {
+ return false;
+ }
+ XmlUtils.writeMapXml(mMap, str);
+ str.close();
+ setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
+ if (FileUtils.getFileStatus(mFile.getPath(), mFileStatus)) {
+ mTimestamp = mFileStatus.mtime;
+ }
+
+ // Writing was successful, delete the backup file if there is one.
+ mBackupFile.delete();
+ return true;
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "writeFileLocked: Got exception:", e);
+ } catch (IOException e) {
+ Log.w(TAG, "writeFileLocked: Got exception:", e);
+ }
+ // Clean up an unsuccessfully written file
+ if (mFile.exists()) {
+ if (!mFile.delete()) {
+ Log.e(TAG, "Couldn't clean up partially-written file " + mFile);
+ }
+ }
+ return false;
+ }
+ }
+}