| /* |
| * 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.common.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.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.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 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 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 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 = {}; |
| |
| @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 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, false).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 (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(); |
| } |
| |
| 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 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 = new DevicePolicyManager(this, |
| mMainThread.getHandler()); |
| } |
| } |
| return mDevicePolicyManager; |
| } |
| |
| @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() { |
| ++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 (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 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) { |
| final int icon = info.icon; |
| if (icon != 0) { |
| ResourceName name = new ResourceName(info, icon); |
| Drawable dr = getCachedIcon(name); |
| if (dr != null) { |
| return dr; |
| } |
| try { |
| Resources r = getResourcesForApplication(info); |
| dr = r.getDrawable(icon); |
| if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x" |
| + Integer.toHexString(icon) + " from " + r |
| + ": " + dr); |
| putCachedIcon(name, dr); |
| return dr; |
| } catch (NameNotFoundException e) { |
| Log.w("PackageManager", "Failure retrieving resources for" |
| + info.packageName); |
| } catch (RuntimeException e) { |
| // If an exception was thrown, fall through to return |
| // default icon. |
| Log.w("PackageManager", "Failure retrieving app icon", e); |
| } |
| } |
| return getDefaultActivityIcon(); |
| } |
| |
| @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 establishPackageRemovedReceiver() { |
| // mContext.registerReceiverInternal() winds up acquiring the |
| // main ActivityManagerService.this lock. If we hold our usual |
| // sSync global lock at the same time, we impose a required ordering |
| // on those two locks, which is not good for deadlock prevention. |
| // Use a dedicated lock around initialization of |
| // sPackageRemovedReceiver to avoid this. |
| synchronized (sPackageRemovedSync) { |
| if (sPackageRemovedReceiver == null) { |
| sPackageRemovedReceiver = new PackageRemovedReceiver(); |
| IntentFilter filter = new IntentFilter( |
| Intent.ACTION_PACKAGE_REMOVED); |
| filter.addDataScheme("package"); |
| mContext.registerReceiverInternal(sPackageRemovedReceiver, |
| filter, null, null, null); |
| // Register for events related to sdcard installation. |
| IntentFilter sdFilter = new IntentFilter(); |
| sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); |
| mContext.registerReceiverInternal(sPackageRemovedReceiver, |
| sdFilter, null, null, null); |
| } |
| } |
| } |
| |
| private void putCachedIcon(ResourceName name, Drawable dr) { |
| establishPackageRemovedReceiver(); |
| |
| synchronized (sSync) { |
| sIconCache.put(name, new WeakReference<Drawable>(dr)); |
| if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for " |
| + name + ": " + dr); |
| } |
| } |
| |
| private static final class PackageRemovedReceiver extends BroadcastReceiver { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| String pkgList[] = null; |
| String action = intent.getAction(); |
| boolean immediateGc = false; |
| if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { |
| pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); |
| immediateGc = true; |
| } else { |
| Uri data = intent.getData(); |
| if (data != null) { |
| String ssp = data.getSchemeSpecificPart(); |
| if (ssp != null) { |
| pkgList = new String[] { ssp }; |
| } |
| } |
| } |
| if (pkgList != null && (pkgList.length > 0)) { |
| boolean needCleanup = false; |
| boolean hasPkgInfo = false; |
| for (String ssp : pkgList) { |
| synchronized (sSync) { |
| 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; |
| } |
| } |
| 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 (!hasPkgInfo) { |
| hasPkgInfo = ActivityThread.currentActivityThread().hasPackageInfo(ssp); |
| } |
| } |
| 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) { |
| establishPackageRemovedReceiver(); |
| |
| synchronized (sSync) { |
| sStringCache.put(name, new WeakReference<CharSequence>(cs)); |
| } |
| } |
| |
| private CharSequence getLabel(ResourceName name, ApplicationInfo app, int id) { |
| CharSequence cs = getCachedString(name); |
| if (cs != null) { |
| return cs; |
| } |
| try { |
| Resources r = getResourcesForApplication(app); |
| cs = r.getText(id); |
| putCachedString(name, cs); |
| } catch (NameNotFoundException e) { |
| Log.w("PackageManager", "Failure retrieving resources for" |
| + app.packageName); |
| } catch (RuntimeException e) { |
| // If an exception was thrown, fall through to return null |
| Log.w("ApplicationInfo", "Failure retrieving activity name", e); |
| } |
| return 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) { |
| if (info.nonLocalizedLabel != null) { |
| return info.nonLocalizedLabel; |
| } |
| final int id = info.labelRes; |
| if (id != 0) { |
| CharSequence cs = getLabel(new ResourceName(info, id), info, id); |
| if (cs != null) { |
| return cs; |
| } |
| } |
| return info.packageName; |
| } |
| |
| @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 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; |
| } |
| |
| // Constants related to app heuristics |
| // No-installation limit for internal flash: 10% or less space available |
| private static final double LOW_NAND_FLASH_TRESHOLD = 0.1; |
| |
| // SD-to-internal app size threshold: currently set to 1 MB |
| private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024); |
| |
| public int recommendAppInstallLocation(Package pkg) { |
| // Initial implementation: |
| // Package size = code size + cache size + data size |
| // If code size > 1 MB, install on SD card. |
| // Else install on internal NAND flash, unless space on NAND is less than 10% |
| |
| if (pkg == null) { |
| return INSTALL_PARSE_FAILED_NOT_APK; |
| } |
| |
| StatFs internalFlashStats = new StatFs(Environment.getDataDirectory().getPath()); |
| StatFs sdcardStats = new StatFs(Environment.getExternalStorageDirectory().getPath()); |
| |
| long totalInternalFlashSize = (long)internalFlashStats.getBlockCount() * |
| (long)internalFlashStats.getBlockSize(); |
| long availInternalFlashSize = (long)internalFlashStats.getAvailableBlocks() * |
| (long)internalFlashStats.getBlockSize(); |
| long availSDSize = (long)sdcardStats.getAvailableBlocks() * |
| (long)sdcardStats.getBlockSize(); |
| |
| double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize; |
| |
| final String archiveFilePath = pkg.mScanPath; |
| File apkFile = new File(archiveFilePath); |
| long pkgLen = apkFile.length(); |
| |
| boolean auto = true; |
| // To make final copy |
| long reqInstallSize = pkgLen; |
| // For dex files |
| long reqInternalSize = 1 * pkgLen; |
| boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD); |
| boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalFlashSize); |
| boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk && |
| (reqInternalSize < availInternalFlashSize); |
| boolean fitsOnInt = intThresholdOk && intAvailOk; |
| |
| // Consider application flags preferences as well... |
| boolean installOnlyOnSd = (pkg.installLocation == |
| PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); |
| boolean installOnlyInternal = (pkg.installLocation == |
| PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); |
| if (installOnlyInternal) { |
| // If set explicitly in manifest, |
| // let that override everything else |
| auto = false; |
| } else if (installOnlyOnSd){ |
| // Check if this can be accommodated on the sdcard |
| if (fitsOnSd) { |
| auto = false; |
| } |
| } else { |
| // Check if user option is enabled |
| boolean setInstallLoc = Settings.System.getInt(mContext.getContentResolver(), |
| Settings.System.SET_INSTALL_LOCATION, 0) != 0; |
| if (setInstallLoc) { |
| // Pick user preference |
| int installPreference = Settings.System.getInt(mContext.getContentResolver(), |
| Settings.System.DEFAULT_INSTALL_LOCATION, |
| PackageInfo.INSTALL_LOCATION_AUTO); |
| if (installPreference == 1) { |
| installOnlyInternal = true; |
| auto = false; |
| } else if (installPreference == 2) { |
| installOnlyOnSd = true; |
| auto = false; |
| } |
| } |
| } |
| if (!auto) { |
| if (installOnlyOnSd) { |
| return fitsOnSd ? INSTALL_ON_SDCARD : INSTALL_FAILED_INSUFFICIENT_STORAGE; |
| } else if (installOnlyInternal){ |
| // Check on internal flash |
| return fitsOnInt ? INSTALL_ON_INTERNAL_FLASH : INSTALL_FAILED_INSUFFICIENT_STORAGE; |
| } |
| } |
| // Try to install internally |
| if (fitsOnInt) { |
| return INSTALL_ON_INTERNAL_FLASH; |
| } |
| // Try the sdcard now. |
| if (fitsOnSd) { |
| return INSTALL_ON_SDCARD; |
| } |
| // Return error code |
| return INSTALL_FAILED_INSUFFICIENT_STORAGE; |
| } |
| |
| private final ContextImpl mContext; |
| private final IPackageManager mPM; |
| |
| private static final Object sSync = new Object(); |
| private static final Object sPackageRemovedSync = new Object(); |
| private static BroadcastReceiver sPackageRemovedReceiver; |
| 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 (!mFile.renameTo(mBackupFile)) { |
| Log.e(TAG, "Couldn't rename file " + mFile + " to backup file " + mBackupFile); |
| return false; |
| } |
| } |
| |
| // 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; |
| } |
| } |
| } |