| /* |
| * 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 android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.content.BroadcastReceiver; |
| import android.content.ComponentName; |
| import android.content.ContentProvider; |
| import android.content.ContentResolver; |
| import android.content.Context; |
| import android.content.ContextWrapper; |
| import android.content.IContentProvider; |
| import android.content.IIntentReceiver; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| 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.IPackageManager; |
| import android.content.pm.PackageManager; |
| import android.content.pm.PackageManager.NameNotFoundException; |
| import android.content.res.AssetManager; |
| import android.content.res.CompatResources; |
| import android.content.res.CompatibilityInfo; |
| import android.content.res.Configuration; |
| import android.content.res.Resources; |
| import android.database.DatabaseErrorHandler; |
| import android.database.sqlite.SQLiteDatabase; |
| import android.database.sqlite.SQLiteDatabase.CursorFactory; |
| import android.graphics.Bitmap; |
| import android.graphics.drawable.Drawable; |
| import android.net.Uri; |
| import android.os.Binder; |
| import android.os.Build; |
| import android.os.Bundle; |
| import android.os.Debug; |
| import android.os.Environment; |
| import android.os.FileUtils; |
| import android.os.Handler; |
| import android.os.IBinder; |
| import android.os.Looper; |
| import android.os.Process; |
| import android.os.RemoteException; |
| import android.os.Trace; |
| import android.os.UserHandle; |
| import android.os.UserManager; |
| import android.os.storage.StorageManager; |
| import android.system.ErrnoException; |
| import android.system.Os; |
| import android.system.OsConstants; |
| import android.system.StructStat; |
| import android.util.AndroidRuntimeException; |
| import android.util.ArrayMap; |
| import android.util.Log; |
| import android.util.Slog; |
| import android.view.Display; |
| import android.view.DisplayAdjustments; |
| import android.view.autofill.AutofillManager.AutofillClient; |
| |
| import com.android.internal.annotations.GuardedBy; |
| import com.android.internal.util.Preconditions; |
| |
| import libcore.io.Memory; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.FilenameFilter; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.nio.ByteOrder; |
| import java.util.ArrayList; |
| import java.util.Objects; |
| import java.util.concurrent.Executor; |
| |
| 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) { |
| if (receiver == null) { |
| // Allow retrieving current sticky broadcast; this is safe since we |
| // aren't actually registering a receiver. |
| return super.registerReceiver(null, filter, broadcastPermission, scheduler); |
| } else { |
| throw new ReceiverCallNotAllowedException( |
| "BroadcastReceiver components are not allowed to register to receive intents"); |
| } |
| } |
| |
| @Override |
| public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, |
| IntentFilter filter, String broadcastPermission, Handler scheduler) { |
| if (receiver == null) { |
| // Allow retrieving current sticky broadcast; this is safe since we |
| // aren't actually registering a receiver. |
| return super.registerReceiverAsUser(null, user, filter, broadcastPermission, scheduler); |
| } else { |
| throw new ReceiverCallNotAllowedException( |
| "BroadcastReceiver components are not allowed to register to receive intents"); |
| } |
| } |
| |
| @Override |
| public boolean bindService(Intent service, ServiceConnection conn, int flags) { |
| throw new ReceiverCallNotAllowedException( |
| "BroadcastReceiver components are not allowed to bind to services"); |
| } |
| } |
| |
| /** |
| * 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 = "ContextImpl"; |
| private final static boolean DEBUG = false; |
| |
| private static final String XATTR_INODE_CACHE = "user.inode_cache"; |
| private static final String XATTR_INODE_CODE_CACHE = "user.inode_code_cache"; |
| |
| /** |
| * Map from package name, to preference name, to cached preferences. |
| */ |
| @GuardedBy("ContextImpl.class") |
| private static ArrayMap<String, ArrayMap<File, SharedPreferencesImpl>> sSharedPrefsCache; |
| |
| /** |
| * Map from preference name to generated path. |
| */ |
| @GuardedBy("ContextImpl.class") |
| private ArrayMap<String, File> mSharedPrefsPaths; |
| |
| final @NonNull ActivityThread mMainThread; |
| final @NonNull LoadedApk mPackageInfo; |
| private @Nullable ClassLoader mClassLoader; |
| |
| private final @Nullable IBinder mActivityToken; |
| |
| private final @NonNull UserHandle mUser; |
| |
| private final ApplicationContentResolver mContentResolver; |
| |
| private final String mBasePackageName; |
| private final String mOpPackageName; |
| |
| private final @NonNull ResourcesManager mResourcesManager; |
| private @NonNull Resources mResources; |
| private @Nullable Display mDisplay; // may be null if default display |
| |
| private final int mFlags; |
| |
| private Context mOuterContext; |
| private int mThemeResource = 0; |
| private Resources.Theme mTheme = null; |
| private PackageManager mPackageManager; |
| private Context mReceiverRestrictedContext = null; |
| |
| // The name of the split this Context is representing. May be null. |
| private @Nullable String mSplitName = null; |
| |
| private AutofillClient mAutofillClient = null; |
| private boolean mIsAutofillCompatEnabled; |
| |
| private final Object mSync = new Object(); |
| |
| @GuardedBy("mSync") |
| private File mDatabasesDir; |
| @GuardedBy("mSync") |
| private File mPreferencesDir; |
| @GuardedBy("mSync") |
| private File mFilesDir; |
| @GuardedBy("mSync") |
| private File mNoBackupFilesDir; |
| @GuardedBy("mSync") |
| private File mCacheDir; |
| @GuardedBy("mSync") |
| private File mCodeCacheDir; |
| |
| // The system service cache for the system services that are cached per-ContextImpl. |
| final Object[] mServiceCache = SystemServiceRegistry.createServiceCache(); |
| |
| static ContextImpl getImpl(Context context) { |
| Context nextContext; |
| while ((context instanceof ContextWrapper) && |
| (nextContext=((ContextWrapper)context).getBaseContext()) != null) { |
| context = nextContext; |
| } |
| return (ContextImpl)context; |
| } |
| |
| @Override |
| public AssetManager getAssets() { |
| return getResources().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 Executor getMainExecutor() { |
| return mMainThread.getExecutor(); |
| } |
| |
| @Override |
| public Context getApplicationContext() { |
| return (mPackageInfo != null) ? |
| mPackageInfo.getApplication() : mMainThread.getApplication(); |
| } |
| |
| @Override |
| public void setTheme(int resId) { |
| synchronized (mSync) { |
| if (mThemeResource != resId) { |
| mThemeResource = resId; |
| initializeTheme(); |
| } |
| } |
| } |
| |
| @Override |
| public int getThemeResId() { |
| synchronized (mSync) { |
| return mThemeResource; |
| } |
| } |
| |
| @Override |
| public Resources.Theme getTheme() { |
| synchronized (mSync) { |
| if (mTheme != null) { |
| return mTheme; |
| } |
| |
| mThemeResource = Resources.selectDefaultTheme(mThemeResource, |
| getOuterContext().getApplicationInfo().targetSdkVersion); |
| initializeTheme(); |
| |
| return mTheme; |
| } |
| } |
| |
| private void initializeTheme() { |
| if (mTheme == null) { |
| mTheme = mResources.newTheme(); |
| } |
| mTheme.applyStyle(mThemeResource, true); |
| } |
| |
| @Override |
| public ClassLoader getClassLoader() { |
| return mClassLoader != null ? mClassLoader : (mPackageInfo != null ? mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader()); |
| } |
| |
| @Override |
| public String getPackageName() { |
| if (mPackageInfo != null) { |
| return mPackageInfo.getPackageName(); |
| } |
| // No mPackageInfo means this is a Context for the system itself, |
| // and this here is its name. |
| return "android"; |
| } |
| |
| /** @hide */ |
| @Override |
| public String getBasePackageName() { |
| return mBasePackageName != null ? mBasePackageName : getPackageName(); |
| } |
| |
| /** @hide */ |
| @Override |
| public String getOpPackageName() { |
| return mOpPackageName != null ? mOpPackageName : getBasePackageName(); |
| } |
| |
| @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"); |
| } |
| |
| @Override |
| public SharedPreferences getSharedPreferences(String name, int mode) { |
| // At least one application in the world actually passes in a null |
| // name. This happened to work because when we generated the file name |
| // we would stringify it to "null.xml". Nice. |
| if (mPackageInfo.getApplicationInfo().targetSdkVersion < |
| Build.VERSION_CODES.KITKAT) { |
| if (name == null) { |
| name = "null"; |
| } |
| } |
| |
| File file; |
| synchronized (ContextImpl.class) { |
| if (mSharedPrefsPaths == null) { |
| mSharedPrefsPaths = new ArrayMap<>(); |
| } |
| file = mSharedPrefsPaths.get(name); |
| if (file == null) { |
| file = getSharedPreferencesPath(name); |
| mSharedPrefsPaths.put(name, file); |
| } |
| } |
| return getSharedPreferences(file, mode); |
| } |
| |
| @Override |
| public SharedPreferences getSharedPreferences(File file, int mode) { |
| SharedPreferencesImpl sp; |
| synchronized (ContextImpl.class) { |
| final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked(); |
| sp = cache.get(file); |
| if (sp == null) { |
| checkMode(mode); |
| if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) { |
| if (isCredentialProtectedStorage() |
| && !getSystemService(UserManager.class) |
| .isUserUnlockingOrUnlocked(UserHandle.myUserId())) { |
| throw new IllegalStateException("SharedPreferences in credential encrypted " |
| + "storage are not available until after user is unlocked"); |
| } |
| } |
| sp = new SharedPreferencesImpl(file, mode); |
| cache.put(file, sp); |
| return sp; |
| } |
| } |
| if ((mode & Context.MODE_MULTI_PROCESS) != 0 || |
| getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) { |
| // If somebody else (some other process) changed the prefs |
| // file behind our back, we reload it. This has been the |
| // historical (if undocumented) behavior. |
| sp.startReloadIfChangedUnexpectedly(); |
| } |
| return sp; |
| } |
| |
| @GuardedBy("ContextImpl.class") |
| private ArrayMap<File, SharedPreferencesImpl> getSharedPreferencesCacheLocked() { |
| if (sSharedPrefsCache == null) { |
| sSharedPrefsCache = new ArrayMap<>(); |
| } |
| |
| final String packageName = getPackageName(); |
| ArrayMap<File, SharedPreferencesImpl> packagePrefs = sSharedPrefsCache.get(packageName); |
| if (packagePrefs == null) { |
| packagePrefs = new ArrayMap<>(); |
| sSharedPrefsCache.put(packageName, packagePrefs); |
| } |
| |
| return packagePrefs; |
| } |
| |
| @Override |
| public void reloadSharedPreferences() { |
| // Build the list of all per-context impls (i.e. caches) we know about |
| ArrayList<SharedPreferencesImpl> spImpls = new ArrayList<>(); |
| synchronized (ContextImpl.class) { |
| final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked(); |
| for (int i = 0; i < cache.size(); i++) { |
| final SharedPreferencesImpl sp = cache.valueAt(i); |
| if (sp != null) { |
| spImpls.add(sp); |
| } |
| } |
| } |
| |
| // Issue the reload outside the cache lock |
| for (int i = 0; i < spImpls.size(); i++) { |
| spImpls.get(i).startReloadIfChangedUnexpectedly(); |
| } |
| } |
| |
| /** |
| * Try our best to migrate all files from source to target that match |
| * requested prefix. |
| * |
| * @return the number of files moved, or -1 if there was trouble. |
| */ |
| private static int moveFiles(File sourceDir, File targetDir, final String prefix) { |
| final File[] sourceFiles = FileUtils.listFilesOrEmpty(sourceDir, new FilenameFilter() { |
| @Override |
| public boolean accept(File dir, String name) { |
| return name.startsWith(prefix); |
| } |
| }); |
| |
| int res = 0; |
| for (File sourceFile : sourceFiles) { |
| final File targetFile = new File(targetDir, sourceFile.getName()); |
| Log.d(TAG, "Migrating " + sourceFile + " to " + targetFile); |
| try { |
| FileUtils.copyFileOrThrow(sourceFile, targetFile); |
| FileUtils.copyPermissions(sourceFile, targetFile); |
| if (!sourceFile.delete()) { |
| throw new IOException("Failed to clean up " + sourceFile); |
| } |
| if (res != -1) { |
| res++; |
| } |
| } catch (IOException e) { |
| Log.w(TAG, "Failed to migrate " + sourceFile + ": " + e); |
| res = -1; |
| } |
| } |
| return res; |
| } |
| |
| @Override |
| public boolean moveSharedPreferencesFrom(Context sourceContext, String name) { |
| synchronized (ContextImpl.class) { |
| final File source = sourceContext.getSharedPreferencesPath(name); |
| final File target = getSharedPreferencesPath(name); |
| |
| final int res = moveFiles(source.getParentFile(), target.getParentFile(), |
| source.getName()); |
| if (res > 0) { |
| // We moved at least one file, so evict any in-memory caches for |
| // either location |
| final ArrayMap<File, SharedPreferencesImpl> cache = |
| getSharedPreferencesCacheLocked(); |
| cache.remove(source); |
| cache.remove(target); |
| } |
| return res != -1; |
| } |
| } |
| |
| @Override |
| public boolean deleteSharedPreferences(String name) { |
| synchronized (ContextImpl.class) { |
| final File prefs = getSharedPreferencesPath(name); |
| final File prefsBackup = SharedPreferencesImpl.makeBackupFile(prefs); |
| |
| // Evict any in-memory caches |
| final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked(); |
| cache.remove(prefs); |
| |
| prefs.delete(); |
| prefsBackup.delete(); |
| |
| // We failed if files are still lingering |
| return !(prefs.exists() || prefsBackup.exists()); |
| } |
| } |
| |
| private File getPreferencesDir() { |
| synchronized (mSync) { |
| if (mPreferencesDir == null) { |
| mPreferencesDir = new File(getDataDir(), "shared_prefs"); |
| } |
| return ensurePrivateDirExists(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 { |
| checkMode(mode); |
| 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(); |
| } |
| |
| /** |
| * Common-path handling of app data dir creation |
| */ |
| private static File ensurePrivateDirExists(File file) { |
| return ensurePrivateDirExists(file, 0771, -1, null); |
| } |
| |
| private static File ensurePrivateCacheDirExists(File file, String xattr) { |
| final int gid = UserHandle.getCacheAppGid(Process.myUid()); |
| return ensurePrivateDirExists(file, 02771, gid, xattr); |
| } |
| |
| private static File ensurePrivateDirExists(File file, int mode, int gid, String xattr) { |
| if (!file.exists()) { |
| final String path = file.getAbsolutePath(); |
| try { |
| Os.mkdir(path, mode); |
| Os.chmod(path, mode); |
| if (gid != -1) { |
| Os.chown(path, -1, gid); |
| } |
| } catch (ErrnoException e) { |
| if (e.errno == OsConstants.EEXIST) { |
| // We must have raced with someone; that's okay |
| } else { |
| Log.w(TAG, "Failed to ensure " + file + ": " + e.getMessage()); |
| } |
| } |
| |
| if (xattr != null) { |
| try { |
| final StructStat stat = Os.stat(file.getAbsolutePath()); |
| final byte[] value = new byte[8]; |
| Memory.pokeLong(value, 0, stat.st_ino, ByteOrder.nativeOrder()); |
| Os.setxattr(file.getParentFile().getAbsolutePath(), xattr, value, 0); |
| } catch (ErrnoException e) { |
| Log.w(TAG, "Failed to update " + xattr + ": " + e.getMessage()); |
| } |
| } |
| } |
| return file; |
| } |
| |
| @Override |
| public File getFilesDir() { |
| synchronized (mSync) { |
| if (mFilesDir == null) { |
| mFilesDir = new File(getDataDir(), "files"); |
| } |
| return ensurePrivateDirExists(mFilesDir); |
| } |
| } |
| |
| @Override |
| public File getNoBackupFilesDir() { |
| synchronized (mSync) { |
| if (mNoBackupFilesDir == null) { |
| mNoBackupFilesDir = new File(getDataDir(), "no_backup"); |
| } |
| return ensurePrivateDirExists(mNoBackupFilesDir); |
| } |
| } |
| |
| @Override |
| public File getExternalFilesDir(String type) { |
| // Operates on primary external storage |
| final File[] dirs = getExternalFilesDirs(type); |
| return (dirs != null && dirs.length > 0) ? dirs[0] : null; |
| } |
| |
| @Override |
| public File[] getExternalFilesDirs(String type) { |
| synchronized (mSync) { |
| File[] dirs = Environment.buildExternalStorageAppFilesDirs(getPackageName()); |
| if (type != null) { |
| dirs = Environment.buildPaths(dirs, type); |
| } |
| return ensureExternalDirsExistOrFilter(dirs); |
| } |
| } |
| |
| @Override |
| public File getObbDir() { |
| // Operates on primary external storage |
| final File[] dirs = getObbDirs(); |
| return (dirs != null && dirs.length > 0) ? dirs[0] : null; |
| } |
| |
| @Override |
| public File[] getObbDirs() { |
| synchronized (mSync) { |
| File[] dirs = Environment.buildExternalStorageAppObbDirs(getPackageName()); |
| return ensureExternalDirsExistOrFilter(dirs); |
| } |
| } |
| |
| @Override |
| public File getCacheDir() { |
| synchronized (mSync) { |
| if (mCacheDir == null) { |
| mCacheDir = new File(getDataDir(), "cache"); |
| } |
| return ensurePrivateCacheDirExists(mCacheDir, XATTR_INODE_CACHE); |
| } |
| } |
| |
| @Override |
| public File getCodeCacheDir() { |
| synchronized (mSync) { |
| if (mCodeCacheDir == null) { |
| mCodeCacheDir = new File(getDataDir(), "code_cache"); |
| } |
| return ensurePrivateCacheDirExists(mCodeCacheDir, XATTR_INODE_CODE_CACHE); |
| } |
| } |
| |
| @Override |
| public File getExternalCacheDir() { |
| // Operates on primary external storage |
| final File[] dirs = getExternalCacheDirs(); |
| return (dirs != null && dirs.length > 0) ? dirs[0] : null; |
| } |
| |
| @Override |
| public File[] getExternalCacheDirs() { |
| synchronized (mSync) { |
| File[] dirs = Environment.buildExternalStorageAppCacheDirs(getPackageName()); |
| return ensureExternalDirsExistOrFilter(dirs); |
| } |
| } |
| |
| @Override |
| public File[] getExternalMediaDirs() { |
| synchronized (mSync) { |
| File[] dirs = Environment.buildExternalStorageAppMediaDirs(getPackageName()); |
| return ensureExternalDirsExistOrFilter(dirs); |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| @Nullable |
| @Override |
| public File getPreloadsFileCache() { |
| return Environment.getDataPreloadsFileCacheDirectory(getPackageName()); |
| } |
| |
| @Override |
| public File getFileStreamPath(String name) { |
| return makeFilename(getFilesDir(), name); |
| } |
| |
| @Override |
| public File getSharedPreferencesPath(String name) { |
| return makeFilename(getPreferencesDir(), name + ".xml"); |
| } |
| |
| @Override |
| public String[] fileList() { |
| return FileUtils.listOrEmpty(getFilesDir()); |
| } |
| |
| @Override |
| public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) { |
| return openOrCreateDatabase(name, mode, factory, null); |
| } |
| |
| @Override |
| public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory, |
| DatabaseErrorHandler errorHandler) { |
| checkMode(mode); |
| File f = getDatabasePath(name); |
| int flags = SQLiteDatabase.CREATE_IF_NECESSARY; |
| if ((mode & MODE_ENABLE_WRITE_AHEAD_LOGGING) != 0) { |
| flags |= SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING; |
| } |
| if ((mode & MODE_NO_LOCALIZED_COLLATORS) != 0) { |
| flags |= SQLiteDatabase.NO_LOCALIZED_COLLATORS; |
| } |
| SQLiteDatabase db = SQLiteDatabase.openDatabase(f.getPath(), factory, flags, errorHandler); |
| setFilePermissionsFromMode(f.getPath(), mode, 0); |
| return db; |
| } |
| |
| @Override |
| public boolean moveDatabaseFrom(Context sourceContext, String name) { |
| synchronized (ContextImpl.class) { |
| final File source = sourceContext.getDatabasePath(name); |
| final File target = getDatabasePath(name); |
| return moveFiles(source.getParentFile(), target.getParentFile(), |
| source.getName()) != -1; |
| } |
| } |
| |
| @Override |
| public boolean deleteDatabase(String name) { |
| try { |
| File f = getDatabasePath(name); |
| return SQLiteDatabase.deleteDatabase(f); |
| } catch (Exception e) { |
| } |
| return false; |
| } |
| |
| @Override |
| public File getDatabasePath(String name) { |
| 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); |
| |
| if (!dir.isDirectory() && dir.mkdir()) { |
| FileUtils.setPermissions(dir.getPath(), |
| FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, |
| -1, -1); |
| } |
| } else { |
| dir = getDatabasesDir(); |
| f = makeFilename(dir, name); |
| } |
| |
| return f; |
| } |
| |
| @Override |
| public String[] databaseList() { |
| return FileUtils.listOrEmpty(getDatabasesDir()); |
| } |
| |
| private File getDatabasesDir() { |
| synchronized (mSync) { |
| if (mDatabasesDir == null) { |
| if ("android".equals(getPackageName())) { |
| mDatabasesDir = new File("/data/system"); |
| } else { |
| mDatabasesDir = new File(getDataDir(), "databases"); |
| } |
| } |
| return ensurePrivateDirExists(mDatabasesDir); |
| } |
| } |
| |
| @Override |
| @Deprecated |
| public Drawable getWallpaper() { |
| return getWallpaperManager().getDrawable(); |
| } |
| |
| @Override |
| @Deprecated |
| public Drawable peekWallpaper() { |
| return getWallpaperManager().peekDrawable(); |
| } |
| |
| @Override |
| @Deprecated |
| public int getWallpaperDesiredMinimumWidth() { |
| return getWallpaperManager().getDesiredMinimumWidth(); |
| } |
| |
| @Override |
| @Deprecated |
| public int getWallpaperDesiredMinimumHeight() { |
| return getWallpaperManager().getDesiredMinimumHeight(); |
| } |
| |
| @Override |
| @Deprecated |
| public void setWallpaper(Bitmap bitmap) throws IOException { |
| getWallpaperManager().setBitmap(bitmap); |
| } |
| |
| @Override |
| @Deprecated |
| public void setWallpaper(InputStream data) throws IOException { |
| getWallpaperManager().setStream(data); |
| } |
| |
| @Override |
| @Deprecated |
| public void clearWallpaper() throws IOException { |
| getWallpaperManager().clear(); |
| } |
| |
| private WallpaperManager getWallpaperManager() { |
| return getSystemService(WallpaperManager.class); |
| } |
| |
| @Override |
| public void startActivity(Intent intent) { |
| warnIfCallingFromSystemProcess(); |
| startActivity(intent, null); |
| } |
| |
| /** @hide */ |
| @Override |
| public void startActivityAsUser(Intent intent, UserHandle user) { |
| startActivityAsUser(intent, null, user); |
| } |
| |
| @Override |
| public void startActivity(Intent intent, Bundle options) { |
| warnIfCallingFromSystemProcess(); |
| |
| // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is |
| // generally not allowed, except if the caller specifies the task id the activity should |
| // be launched in. A bug was existed between N and O-MR1 which allowed this to work. We |
| // maintain this for backwards compatibility. |
| final int targetSdkVersion = getApplicationInfo().targetSdkVersion; |
| |
| if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 |
| && (targetSdkVersion < Build.VERSION_CODES.N |
| || targetSdkVersion >= Build.VERSION_CODES.P) |
| && (options == null |
| || ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) { |
| 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, |
| (Activity) null, intent, -1, options); |
| } |
| |
| /** @hide */ |
| @Override |
| public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) { |
| try { |
| ActivityManager.getService().startActivityAsUser( |
| mMainThread.getApplicationThread(), getBasePackageName(), intent, |
| intent.resolveTypeIfNeeded(getContentResolver()), |
| null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options, |
| user.getIdentifier()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void startActivities(Intent[] intents) { |
| warnIfCallingFromSystemProcess(); |
| startActivities(intents, null); |
| } |
| |
| /** @hide */ |
| @Override |
| public int startActivitiesAsUser(Intent[] intents, Bundle options, UserHandle userHandle) { |
| if ((intents[0].getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { |
| throw new AndroidRuntimeException( |
| "Calling startActivities() from outside of an Activity " |
| + " context requires the FLAG_ACTIVITY_NEW_TASK flag on first Intent." |
| + " Is this really what you want?"); |
| } |
| return mMainThread.getInstrumentation().execStartActivitiesAsUser( |
| getOuterContext(), mMainThread.getApplicationThread(), null, |
| (Activity) null, intents, options, userHandle.getIdentifier()); |
| } |
| |
| @Override |
| public void startActivities(Intent[] intents, Bundle options) { |
| warnIfCallingFromSystemProcess(); |
| if ((intents[0].getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { |
| throw new AndroidRuntimeException( |
| "Calling startActivities() from outside of an Activity " |
| + " context requires the FLAG_ACTIVITY_NEW_TASK flag on first Intent." |
| + " Is this really what you want?"); |
| } |
| mMainThread.getInstrumentation().execStartActivities( |
| getOuterContext(), mMainThread.getApplicationThread(), null, |
| (Activity) null, intents, options); |
| } |
| |
| @Override |
| public void startIntentSender(IntentSender intent, |
| Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags) |
| throws IntentSender.SendIntentException { |
| startIntentSender(intent, fillInIntent, flagsMask, flagsValues, extraFlags, null); |
| } |
| |
| @Override |
| public void startIntentSender(IntentSender intent, Intent fillInIntent, |
| int flagsMask, int flagsValues, int extraFlags, Bundle options) |
| throws IntentSender.SendIntentException { |
| try { |
| String resolvedType = null; |
| if (fillInIntent != null) { |
| fillInIntent.migrateExtraStreamToClipData(); |
| fillInIntent.prepareToLeaveProcess(this); |
| resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver()); |
| } |
| int result = ActivityManager.getService() |
| .startActivityIntentSender(mMainThread.getApplicationThread(), |
| intent != null ? intent.getTarget() : null, |
| intent != null ? intent.getWhitelistToken() : null, |
| fillInIntent, resolvedType, null, null, |
| 0, flagsMask, flagsValues, options); |
| if (result == ActivityManager.START_CANCELED) { |
| throw new IntentSender.SendIntentException(); |
| } |
| Instrumentation.checkStartActivityResult(result, null); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void sendBroadcast(Intent intent) { |
| warnIfCallingFromSystemProcess(); |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, null, |
| Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, |
| getUserId()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void sendBroadcast(Intent intent, String receiverPermission) { |
| warnIfCallingFromSystemProcess(); |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| String[] receiverPermissions = receiverPermission == null ? null |
| : new String[] {receiverPermission}; |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, null, |
| Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, |
| null, false, false, getUserId()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) { |
| warnIfCallingFromSystemProcess(); |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, null, |
| Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, |
| null, false, false, getUserId()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { |
| warnIfCallingFromSystemProcess(); |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| String[] receiverPermissions = receiverPermission == null ? null |
| : new String[] {receiverPermission}; |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, null, |
| Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, |
| options, false, false, getUserId()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void sendBroadcast(Intent intent, String receiverPermission, int appOp) { |
| warnIfCallingFromSystemProcess(); |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| String[] receiverPermissions = receiverPermission == null ? null |
| : new String[] {receiverPermission}; |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, null, |
| Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false, |
| getUserId()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void sendOrderedBroadcast(Intent intent, String receiverPermission) { |
| warnIfCallingFromSystemProcess(); |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| String[] receiverPermissions = receiverPermission == null ? null |
| : new String[] {receiverPermission}; |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, null, |
| Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, |
| null, true, false, getUserId()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void sendOrderedBroadcast(Intent intent, |
| String receiverPermission, BroadcastReceiver resultReceiver, |
| Handler scheduler, int initialCode, String initialData, |
| Bundle initialExtras) { |
| sendOrderedBroadcast(intent, receiverPermission, AppOpsManager.OP_NONE, |
| resultReceiver, scheduler, initialCode, initialData, initialExtras, null); |
| } |
| |
| @Override |
| public void sendOrderedBroadcast(Intent intent, |
| String receiverPermission, Bundle options, BroadcastReceiver resultReceiver, |
| Handler scheduler, int initialCode, String initialData, |
| Bundle initialExtras) { |
| sendOrderedBroadcast(intent, receiverPermission, AppOpsManager.OP_NONE, |
| resultReceiver, scheduler, initialCode, initialData, initialExtras, options); |
| } |
| |
| @Override |
| public void sendOrderedBroadcast(Intent intent, |
| String receiverPermission, int appOp, BroadcastReceiver resultReceiver, |
| Handler scheduler, int initialCode, String initialData, |
| Bundle initialExtras) { |
| sendOrderedBroadcast(intent, receiverPermission, appOp, |
| resultReceiver, scheduler, initialCode, initialData, initialExtras, null); |
| } |
| |
| void sendOrderedBroadcast(Intent intent, |
| String receiverPermission, int appOp, BroadcastReceiver resultReceiver, |
| Handler scheduler, int initialCode, String initialData, |
| Bundle initialExtras, Bundle options) { |
| warnIfCallingFromSystemProcess(); |
| 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 LoadedApk.ReceiverDispatcher( |
| resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver(); |
| } |
| } |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| String[] receiverPermissions = receiverPermission == null ? null |
| : new String[] {receiverPermission}; |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, rd, |
| initialCode, initialData, initialExtras, receiverPermissions, appOp, |
| options, true, false, getUserId()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void sendBroadcastAsUser(Intent intent, UserHandle user) { |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent(mMainThread.getApplicationThread(), |
| intent, resolvedType, null, Activity.RESULT_OK, null, null, null, |
| AppOpsManager.OP_NONE, null, false, false, user.getIdentifier()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void sendBroadcastAsUser(Intent intent, UserHandle user, |
| String receiverPermission) { |
| sendBroadcastAsUser(intent, user, receiverPermission, AppOpsManager.OP_NONE); |
| } |
| |
| @Override |
| public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, |
| Bundle options) { |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| String[] receiverPermissions = receiverPermission == null ? null |
| : new String[] {receiverPermission}; |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, null, |
| Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, |
| options, false, false, user.getIdentifier()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void sendBroadcastAsUser(Intent intent, UserHandle user, |
| String receiverPermission, int appOp) { |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| String[] receiverPermissions = receiverPermission == null ? null |
| : new String[] {receiverPermission}; |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, null, |
| Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false, |
| user.getIdentifier()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, |
| String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, |
| int initialCode, String initialData, Bundle initialExtras) { |
| sendOrderedBroadcastAsUser(intent, user, receiverPermission, AppOpsManager.OP_NONE, |
| null, resultReceiver, scheduler, initialCode, initialData, initialExtras); |
| } |
| |
| @Override |
| public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, |
| String receiverPermission, int appOp, BroadcastReceiver resultReceiver, |
| Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { |
| sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, |
| null, resultReceiver, scheduler, initialCode, initialData, initialExtras); |
| } |
| |
| @Override |
| public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, |
| String receiverPermission, int appOp, Bundle options, 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 LoadedApk.ReceiverDispatcher(resultReceiver, getOuterContext(), |
| scheduler, null, false).getIIntentReceiver(); |
| } |
| } |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| String[] receiverPermissions = receiverPermission == null ? null |
| : new String[] {receiverPermission}; |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, rd, |
| initialCode, initialData, initialExtras, receiverPermissions, |
| appOp, options, true, false, user.getIdentifier()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| @Deprecated |
| public void sendStickyBroadcast(Intent intent) { |
| warnIfCallingFromSystemProcess(); |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, null, |
| Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true, |
| getUserId()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| @Deprecated |
| public void sendStickyOrderedBroadcast(Intent intent, |
| BroadcastReceiver resultReceiver, |
| Handler scheduler, int initialCode, String initialData, |
| Bundle initialExtras) { |
| warnIfCallingFromSystemProcess(); |
| 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 LoadedApk.ReceiverDispatcher( |
| resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver(); |
| } |
| } |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, rd, |
| initialCode, initialData, initialExtras, null, |
| AppOpsManager.OP_NONE, null, true, true, getUserId()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| @Deprecated |
| public void removeStickyBroadcast(Intent intent) { |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| if (resolvedType != null) { |
| intent = new Intent(intent); |
| intent.setDataAndType(intent.getData(), resolvedType); |
| } |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().unbroadcastIntent( |
| mMainThread.getApplicationThread(), intent, getUserId()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| @Deprecated |
| public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) { |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, null, |
| Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true, |
| user.getIdentifier()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| @Deprecated |
| public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) { |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, null, |
| Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true, |
| user.getIdentifier()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| @Deprecated |
| public void sendStickyOrderedBroadcastAsUser(Intent intent, |
| UserHandle user, 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 LoadedApk.ReceiverDispatcher( |
| resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver(); |
| } |
| } |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().broadcastIntent( |
| mMainThread.getApplicationThread(), intent, resolvedType, rd, |
| initialCode, initialData, initialExtras, null, |
| AppOpsManager.OP_NONE, null, true, true, user.getIdentifier()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| @Deprecated |
| public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) { |
| String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); |
| if (resolvedType != null) { |
| intent = new Intent(intent); |
| intent.setDataAndType(intent.getData(), resolvedType); |
| } |
| try { |
| intent.prepareToLeaveProcess(this); |
| ActivityManager.getService().unbroadcastIntent( |
| mMainThread.getApplicationThread(), intent, user.getIdentifier()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { |
| return registerReceiver(receiver, filter, null, null); |
| } |
| |
| @Override |
| public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, |
| int flags) { |
| return registerReceiver(receiver, filter, null, null, flags); |
| } |
| |
| @Override |
| public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, |
| String broadcastPermission, Handler scheduler) { |
| return registerReceiverInternal(receiver, getUserId(), |
| filter, broadcastPermission, scheduler, getOuterContext(), 0); |
| } |
| |
| @Override |
| public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, |
| String broadcastPermission, Handler scheduler, int flags) { |
| return registerReceiverInternal(receiver, getUserId(), |
| filter, broadcastPermission, scheduler, getOuterContext(), flags); |
| } |
| |
| @Override |
| public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, |
| IntentFilter filter, String broadcastPermission, Handler scheduler) { |
| return registerReceiverInternal(receiver, user.getIdentifier(), |
| filter, broadcastPermission, scheduler, getOuterContext(), 0); |
| } |
| |
| private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, |
| IntentFilter filter, String broadcastPermission, |
| Handler scheduler, Context context, int flags) { |
| 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 LoadedApk.ReceiverDispatcher( |
| receiver, context, scheduler, null, true).getIIntentReceiver(); |
| } |
| } |
| try { |
| final Intent intent = ActivityManager.getService().registerReceiver( |
| mMainThread.getApplicationThread(), mBasePackageName, rd, filter, |
| broadcastPermission, userId, flags); |
| if (intent != null) { |
| intent.setExtrasClassLoader(getClassLoader()); |
| intent.prepareToEnterProcess(); |
| } |
| return intent; |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void unregisterReceiver(BroadcastReceiver receiver) { |
| if (mPackageInfo != null) { |
| IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher( |
| getOuterContext(), receiver); |
| try { |
| ActivityManager.getService().unregisterReceiver(rd); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } else { |
| throw new RuntimeException("Not supported in system context"); |
| } |
| } |
| |
| private void validateServiceIntent(Intent service) { |
| if (service.getComponent() == null && service.getPackage() == null) { |
| if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) { |
| IllegalArgumentException ex = new IllegalArgumentException( |
| "Service Intent must be explicit: " + service); |
| throw ex; |
| } else { |
| Log.w(TAG, "Implicit intents with startService are not safe: " + service |
| + " " + Debug.getCallers(2, 3)); |
| } |
| } |
| } |
| |
| @Override |
| public ComponentName startService(Intent service) { |
| warnIfCallingFromSystemProcess(); |
| return startServiceCommon(service, false, mUser); |
| } |
| |
| @Override |
| public ComponentName startForegroundService(Intent service) { |
| warnIfCallingFromSystemProcess(); |
| return startServiceCommon(service, true, mUser); |
| } |
| |
| @Override |
| public boolean stopService(Intent service) { |
| warnIfCallingFromSystemProcess(); |
| return stopServiceCommon(service, mUser); |
| } |
| |
| @Override |
| public ComponentName startServiceAsUser(Intent service, UserHandle user) { |
| return startServiceCommon(service, false, user); |
| } |
| |
| @Override |
| public ComponentName startForegroundServiceAsUser(Intent service, UserHandle user) { |
| return startServiceCommon(service, true, user); |
| } |
| |
| private ComponentName startServiceCommon(Intent service, boolean requireForeground, |
| UserHandle user) { |
| try { |
| validateServiceIntent(service); |
| service.prepareToLeaveProcess(this); |
| ComponentName cn = ActivityManager.getService().startService( |
| mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded( |
| getContentResolver()), requireForeground, |
| getOpPackageName(), user.getIdentifier()); |
| if (cn != null) { |
| if (cn.getPackageName().equals("!")) { |
| throw new SecurityException( |
| "Not allowed to start service " + service |
| + " without permission " + cn.getClassName()); |
| } else if (cn.getPackageName().equals("!!")) { |
| throw new SecurityException( |
| "Unable to start service " + service |
| + ": " + cn.getClassName()); |
| } else if (cn.getPackageName().equals("?")) { |
| throw new IllegalStateException( |
| "Not allowed to start service " + service + ": " + cn.getClassName()); |
| } |
| } |
| return cn; |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public boolean stopServiceAsUser(Intent service, UserHandle user) { |
| return stopServiceCommon(service, user); |
| } |
| |
| private boolean stopServiceCommon(Intent service, UserHandle user) { |
| try { |
| validateServiceIntent(service); |
| service.prepareToLeaveProcess(this); |
| int res = ActivityManager.getService().stopService( |
| mMainThread.getApplicationThread(), service, |
| service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier()); |
| if (res < 0) { |
| throw new SecurityException( |
| "Not allowed to stop service " + service); |
| } |
| return res != 0; |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public boolean bindService(Intent service, ServiceConnection conn, |
| int flags) { |
| warnIfCallingFromSystemProcess(); |
| return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), getUser()); |
| } |
| |
| /** @hide */ |
| @Override |
| public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags, |
| UserHandle user) { |
| return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), user); |
| } |
| |
| /** @hide */ |
| @Override |
| public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags, |
| Handler handler, UserHandle user) { |
| if (handler == null) { |
| throw new IllegalArgumentException("handler must not be null."); |
| } |
| return bindServiceCommon(service, conn, flags, handler, user); |
| } |
| |
| /** @hide */ |
| @Override |
| public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler, |
| int flags) { |
| return mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags); |
| } |
| |
| /** @hide */ |
| @Override |
| public IApplicationThread getIApplicationThread() { |
| return mMainThread.getApplicationThread(); |
| } |
| |
| /** @hide */ |
| @Override |
| public Handler getMainThreadHandler() { |
| return mMainThread.getHandler(); |
| } |
| |
| private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler |
| handler, UserHandle user) { |
| // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser. |
| IServiceConnection sd; |
| if (conn == null) { |
| throw new IllegalArgumentException("connection is null"); |
| } |
| if (mPackageInfo != null) { |
| sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags); |
| } else { |
| throw new RuntimeException("Not supported in system context"); |
| } |
| validateServiceIntent(service); |
| try { |
| IBinder token = getActivityToken(); |
| if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null |
| && mPackageInfo.getApplicationInfo().targetSdkVersion |
| < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { |
| flags |= BIND_WAIVE_PRIORITY; |
| } |
| service.prepareToLeaveProcess(this); |
| int res = ActivityManager.getService().bindService( |
| mMainThread.getApplicationThread(), getActivityToken(), service, |
| service.resolveTypeIfNeeded(getContentResolver()), |
| sd, flags, getOpPackageName(), user.getIdentifier()); |
| if (res < 0) { |
| throw new SecurityException( |
| "Not allowed to bind to service " + service); |
| } |
| return res != 0; |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void unbindService(ServiceConnection conn) { |
| if (conn == null) { |
| throw new IllegalArgumentException("connection is null"); |
| } |
| if (mPackageInfo != null) { |
| IServiceConnection sd = mPackageInfo.forgetServiceDispatcher( |
| getOuterContext(), conn); |
| try { |
| ActivityManager.getService().unbindService(sd); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } else { |
| throw new RuntimeException("Not supported in system context"); |
| } |
| } |
| |
| @Override |
| public boolean startInstrumentation(ComponentName className, |
| String profileFile, Bundle arguments) { |
| try { |
| if (arguments != null) { |
| arguments.setAllowFds(false); |
| } |
| return ActivityManager.getService().startInstrumentation( |
| className, profileFile, 0, arguments, null, null, getUserId(), |
| null /* ABI override */); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public Object getSystemService(String name) { |
| return SystemServiceRegistry.getSystemService(this, name); |
| } |
| |
| @Override |
| public String getSystemServiceName(Class<?> serviceClass) { |
| return SystemServiceRegistry.getSystemServiceName(serviceClass); |
| } |
| |
| @Override |
| public int checkPermission(String permission, int pid, int uid) { |
| if (permission == null) { |
| throw new IllegalArgumentException("permission is null"); |
| } |
| |
| final IActivityManager am = ActivityManager.getService(); |
| if (am == null) { |
| // Well this is super awkward; we somehow don't have an active |
| // ActivityManager instance. If we're testing a root or system |
| // UID, then they totally have whatever permission this is. |
| final int appId = UserHandle.getAppId(uid); |
| if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) { |
| Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission); |
| return PackageManager.PERMISSION_GRANTED; |
| } |
| } |
| |
| try { |
| return am.checkPermission(permission, pid, uid); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** @hide */ |
| @Override |
| public int checkPermission(String permission, int pid, int uid, IBinder callerToken) { |
| if (permission == null) { |
| throw new IllegalArgumentException("permission is null"); |
| } |
| |
| try { |
| return ActivityManager.getService().checkPermissionWithToken( |
| permission, pid, uid, callerToken); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public int checkCallingPermission(String permission) { |
| if (permission == null) { |
| throw new IllegalArgumentException("permission is null"); |
| } |
| |
| 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()); |
| } |
| |
| @Override |
| public int checkSelfPermission(String permission) { |
| if (permission == null) { |
| throw new IllegalArgumentException("permission is null"); |
| } |
| |
| return checkPermission(permission, Process.myPid(), Process.myUid()); |
| } |
| |
| 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 " |
| : "uid " + uid + " does not have ") + |
| permission + |
| "."); |
| } |
| } |
| |
| @Override |
| public void enforcePermission( |
| String permission, int pid, int uid, String message) { |
| enforce(permission, |
| checkPermission(permission, pid, uid), |
| false, |
| uid, |
| message); |
| } |
| |
| @Override |
| public void enforceCallingPermission(String permission, String message) { |
| enforce(permission, |
| checkCallingPermission(permission), |
| false, |
| Binder.getCallingUid(), |
| message); |
| } |
| |
| @Override |
| 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 { |
| ActivityManager.getService().grantUriPermission( |
| mMainThread.getApplicationThread(), toPackage, |
| ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void revokeUriPermission(Uri uri, int modeFlags) { |
| try { |
| ActivityManager.getService().revokeUriPermission( |
| mMainThread.getApplicationThread(), null, |
| ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public void revokeUriPermission(String targetPackage, Uri uri, int modeFlags) { |
| try { |
| ActivityManager.getService().revokeUriPermission( |
| mMainThread.getApplicationThread(), targetPackage, |
| ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| @Override |
| public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) { |
| try { |
| return ActivityManager.getService().checkUriPermission( |
| ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags, |
| resolveUserId(uri), null); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** @hide */ |
| @Override |
| public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) { |
| try { |
| return ActivityManager.getService().checkUriPermission( |
| ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags, |
| resolveUserId(uri), callerToken); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| private int resolveUserId(Uri uri) { |
| return ContentProvider.getUserIdFromUri(uri, getUserId()); |
| } |
| |
| @Override |
| public int checkCallingUriPermission(Uri uri, int modeFlags) { |
| 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) { |
| StringBuilder builder = new StringBuilder(); |
| if ((uriModeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { |
| builder.append("read and "); |
| } |
| if ((uriModeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { |
| builder.append("write and "); |
| } |
| if ((uriModeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0) { |
| builder.append("persistable and "); |
| } |
| if ((uriModeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0) { |
| builder.append("prefix and "); |
| } |
| |
| if (builder.length() > 5) { |
| builder.setLength(builder.length() - 5); |
| return builder.toString(); |
| } else { |
| 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 + |
| "."); |
| } |
| } |
| |
| @Override |
| public void enforceUriPermission( |
| Uri uri, int pid, int uid, int modeFlags, String message) { |
| enforceForUri( |
| modeFlags, checkUriPermission(uri, pid, uid, modeFlags), |
| false, uid, uri, message); |
| } |
| |
| @Override |
| public void enforceCallingUriPermission( |
| Uri uri, int modeFlags, String message) { |
| enforceForUri( |
| modeFlags, checkCallingUriPermission(uri, modeFlags), |
| false, |
| Binder.getCallingUid(), uri, message); |
| } |
| |
| @Override |
| public void enforceCallingOrSelfUriPermission( |
| Uri uri, int modeFlags, String message) { |
| enforceForUri( |
| modeFlags, |
| checkCallingOrSelfUriPermission(uri, modeFlags), true, |
| Binder.getCallingUid(), uri, message); |
| } |
| |
| @Override |
| 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); |
| } |
| |
| /** |
| * Logs a warning if the system process directly called a method such as |
| * {@link #startService(Intent)} instead of {@link #startServiceAsUser(Intent, UserHandle)}. |
| * The "AsUser" variants allow us to properly enforce the user's restrictions. |
| */ |
| private void warnIfCallingFromSystemProcess() { |
| if (Process.myUid() == Process.SYSTEM_UID) { |
| Slog.w(TAG, "Calling a method in the system process without a qualified user: " |
| + Debug.getCallers(5)); |
| } |
| } |
| |
| private static Resources createResources(IBinder activityToken, LoadedApk pi, String splitName, |
| int displayId, Configuration overrideConfig, CompatibilityInfo compatInfo) { |
| final String[] splitResDirs; |
| final ClassLoader classLoader; |
| try { |
| splitResDirs = pi.getSplitPaths(splitName); |
| classLoader = pi.getSplitClassLoader(splitName); |
| } catch (NameNotFoundException e) { |
| throw new RuntimeException(e); |
| } |
| return ResourcesManager.getInstance().getResources(activityToken, |
| pi.getResDir(), |
| splitResDirs, |
| pi.getOverlayDirs(), |
| pi.getApplicationInfo().sharedLibraryFiles, |
| displayId, |
| overrideConfig, |
| compatInfo, |
| classLoader); |
| } |
| |
| @Override |
| public Context createApplicationContext(ApplicationInfo application, int flags) |
| throws NameNotFoundException { |
| LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(), |
| flags | CONTEXT_REGISTER_PACKAGE); |
| if (pi != null) { |
| ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, |
| new UserHandle(UserHandle.getUserId(application.uid)), flags, null); |
| |
| final int displayId = mDisplay != null |
| ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY; |
| |
| c.setResources(createResources(mActivityToken, pi, null, displayId, null, |
| getDisplayAdjustments(displayId).getCompatibilityInfo())); |
| if (c.mResources != null) { |
| return c; |
| } |
| } |
| |
| throw new PackageManager.NameNotFoundException( |
| "Application package " + application.packageName + " not found"); |
| } |
| |
| @Override |
| public Context createPackageContext(String packageName, int flags) |
| throws NameNotFoundException { |
| return createPackageContextAsUser(packageName, flags, mUser); |
| } |
| |
| @Override |
| public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) |
| throws NameNotFoundException { |
| if (packageName.equals("system") || packageName.equals("android")) { |
| // The system resources are loaded in every application, so we can safely copy |
| // the context without reloading Resources. |
| return new ContextImpl(this, mMainThread, mPackageInfo, null, mActivityToken, user, |
| flags, null); |
| } |
| |
| LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), |
| flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier()); |
| if (pi != null) { |
| ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, user, |
| flags, null); |
| |
| final int displayId = mDisplay != null |
| ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY; |
| |
| c.setResources(createResources(mActivityToken, pi, null, displayId, null, |
| getDisplayAdjustments(displayId).getCompatibilityInfo())); |
| if (c.mResources != null) { |
| return c; |
| } |
| } |
| |
| // Should be a better exception. |
| throw new PackageManager.NameNotFoundException( |
| "Application package " + packageName + " not found"); |
| } |
| |
| @Override |
| public Context createContextForSplit(String splitName) throws NameNotFoundException { |
| if (!mPackageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) { |
| // All Splits are always loaded. |
| return this; |
| } |
| |
| final ClassLoader classLoader = mPackageInfo.getSplitClassLoader(splitName); |
| final String[] paths = mPackageInfo.getSplitPaths(splitName); |
| |
| final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, splitName, |
| mActivityToken, mUser, mFlags, classLoader); |
| |
| final int displayId = mDisplay != null |
| ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY; |
| |
| context.setResources(ResourcesManager.getInstance().getResources( |
| mActivityToken, |
| mPackageInfo.getResDir(), |
| paths, |
| mPackageInfo.getOverlayDirs(), |
| mPackageInfo.getApplicationInfo().sharedLibraryFiles, |
| displayId, |
| null, |
| mPackageInfo.getCompatibilityInfo(), |
| classLoader)); |
| return context; |
| } |
| |
| @Override |
| public Context createConfigurationContext(Configuration overrideConfiguration) { |
| if (overrideConfiguration == null) { |
| throw new IllegalArgumentException("overrideConfiguration must not be null"); |
| } |
| |
| ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, |
| mActivityToken, mUser, mFlags, mClassLoader); |
| |
| final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY; |
| context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId, |
| overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo())); |
| return context; |
| } |
| |
| @Override |
| public Context createDisplayContext(Display display) { |
| if (display == null) { |
| throw new IllegalArgumentException("display must not be null"); |
| } |
| |
| ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, |
| mActivityToken, mUser, mFlags, mClassLoader); |
| |
| final int displayId = display.getDisplayId(); |
| context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId, |
| null, getDisplayAdjustments(displayId).getCompatibilityInfo())); |
| context.mDisplay = display; |
| return context; |
| } |
| |
| @Override |
| public Context createDeviceProtectedStorageContext() { |
| final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE) |
| | Context.CONTEXT_DEVICE_PROTECTED_STORAGE; |
| return new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, mActivityToken, mUser, |
| flags, mClassLoader); |
| } |
| |
| @Override |
| public Context createCredentialProtectedStorageContext() { |
| final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE) |
| | Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE; |
| return new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, mActivityToken, mUser, |
| flags, mClassLoader); |
| } |
| |
| @Override |
| public boolean isRestricted() { |
| return (mFlags & Context.CONTEXT_RESTRICTED) != 0; |
| } |
| |
| @Override |
| public boolean isDeviceProtectedStorage() { |
| return (mFlags & Context.CONTEXT_DEVICE_PROTECTED_STORAGE) != 0; |
| } |
| |
| @Override |
| public boolean isCredentialProtectedStorage() { |
| return (mFlags & Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE) != 0; |
| } |
| |
| @Override |
| public boolean canLoadUnsafeResources() { |
| if (getPackageName().equals(getOpPackageName())) { |
| return true; |
| } |
| return (mFlags & Context.CONTEXT_IGNORE_SECURITY) != 0; |
| } |
| |
| @Override |
| public Display getDisplay() { |
| if (mDisplay == null) { |
| return mResourcesManager.getAdjustedDisplay(Display.DEFAULT_DISPLAY, |
| mResources); |
| } |
| |
| return mDisplay; |
| } |
| |
| @Override |
| public void updateDisplay(int displayId) { |
| mDisplay = mResourcesManager.getAdjustedDisplay(displayId, mResources); |
| } |
| |
| @Override |
| public DisplayAdjustments getDisplayAdjustments(int displayId) { |
| return mResources.getDisplayAdjustments(); |
| } |
| |
| @Override |
| public File getDataDir() { |
| if (mPackageInfo != null) { |
| File res = null; |
| if (isCredentialProtectedStorage()) { |
| res = mPackageInfo.getCredentialProtectedDataDirFile(); |
| } else if (isDeviceProtectedStorage()) { |
| res = mPackageInfo.getDeviceProtectedDataDirFile(); |
| } else { |
| res = mPackageInfo.getDataDirFile(); |
| } |
| |
| if (res != null) { |
| if (!res.exists() && android.os.Process.myUid() == android.os.Process.SYSTEM_UID) { |
| Log.wtf(TAG, "Data directory doesn't exist for package " + getPackageName(), |
| new Throwable()); |
| } |
| return res; |
| } else { |
| throw new RuntimeException( |
| "No data directory found for package " + getPackageName()); |
| } |
| } else { |
| throw new RuntimeException( |
| "No package details found for package " + getPackageName()); |
| } |
| } |
| |
| @Override |
| public File getDir(String name, int mode) { |
| checkMode(mode); |
| name = "app_" + name; |
| File file = makeFilename(getDataDir(), name); |
| if (!file.exists()) { |
| file.mkdir(); |
| setFilePermissionsFromMode(file.getPath(), mode, |
| FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH); |
| } |
| return file; |
| } |
| |
| /** {@hide} */ |
| @Override |
| public UserHandle getUser() { |
| return mUser; |
| } |
| |
| /** {@hide} */ |
| @Override |
| public int getUserId() { |
| return mUser.getIdentifier(); |
| } |
| |
| /** @hide */ |
| @Override |
| public AutofillClient getAutofillClient() { |
| return mAutofillClient; |
| } |
| |
| /** @hide */ |
| @Override |
| public void setAutofillClient(AutofillClient client) { |
| mAutofillClient = client; |
| } |
| |
| /** @hide */ |
| @Override |
| public boolean isAutofillCompatibilityEnabled() { |
| return mIsAutofillCompatEnabled; |
| } |
| |
| /** @hide */ |
| @Override |
| public void setAutofillCompatibilityEnabled(boolean autofillCompatEnabled) { |
| mIsAutofillCompatEnabled = autofillCompatEnabled; |
| } |
| |
| static ContextImpl createSystemContext(ActivityThread mainThread) { |
| LoadedApk packageInfo = new LoadedApk(mainThread); |
| ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, |
| null); |
| context.setResources(packageInfo.getResources()); |
| context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(), |
| context.mResourcesManager.getDisplayMetrics()); |
| return context; |
| } |
| |
| /** |
| * System Context to be used for UI. This Context has resources that can be themed. |
| * Make sure that the created system UI context shares the same LoadedApk as the system context. |
| */ |
| static ContextImpl createSystemUiContext(ContextImpl systemContext) { |
| final LoadedApk packageInfo = systemContext.mPackageInfo; |
| ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null, |
| null, null, 0, null); |
| context.setResources(createResources(null, packageInfo, null, Display.DEFAULT_DISPLAY, null, |
| packageInfo.getCompatibilityInfo())); |
| return context; |
| } |
| |
| static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { |
| if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); |
| ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, |
| null); |
| context.setResources(packageInfo.getResources()); |
| return context; |
| } |
| |
| static ContextImpl createActivityContext(ActivityThread mainThread, |
| LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId, |
| Configuration overrideConfiguration) { |
| if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); |
| |
| String[] splitDirs = packageInfo.getSplitResDirs(); |
| ClassLoader classLoader = packageInfo.getClassLoader(); |
| |
| if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) { |
| Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies"); |
| try { |
| classLoader = packageInfo.getSplitClassLoader(activityInfo.splitName); |
| splitDirs = packageInfo.getSplitPaths(activityInfo.splitName); |
| } catch (NameNotFoundException e) { |
| // Nothing above us can handle a NameNotFoundException, better crash. |
| throw new RuntimeException(e); |
| } finally { |
| Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); |
| } |
| } |
| |
| ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName, |
| activityToken, null, 0, classLoader); |
| |
| // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY. |
| displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY; |
| |
| final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY) |
| ? packageInfo.getCompatibilityInfo() |
| : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; |
| |
| final ResourcesManager resourcesManager = ResourcesManager.getInstance(); |
| |
| // Create the base resources for which all configuration contexts for this Activity |
| // will be rebased upon. |
| context.setResources(resourcesManager.createBaseActivityResources(activityToken, |
| packageInfo.getResDir(), |
| splitDirs, |
| packageInfo.getOverlayDirs(), |
| packageInfo.getApplicationInfo().sharedLibraryFiles, |
| displayId, |
| overrideConfiguration, |
| compatInfo, |
| classLoader)); |
| context.mDisplay = resourcesManager.getAdjustedDisplay(displayId, |
| context.getResources()); |
| return context; |
| } |
| |
| private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread, |
| @NonNull LoadedApk packageInfo, @Nullable String splitName, |
| @Nullable IBinder activityToken, @Nullable UserHandle user, int flags, |
| @Nullable ClassLoader classLoader) { |
| mOuterContext = this; |
| |
| // If creator didn't specify which storage to use, use the default |
| // location for application. |
| if ((flags & (Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE |
| | Context.CONTEXT_DEVICE_PROTECTED_STORAGE)) == 0) { |
| final File dataDir = packageInfo.getDataDirFile(); |
| if (Objects.equals(dataDir, packageInfo.getCredentialProtectedDataDirFile())) { |
| flags |= Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE; |
| } else if (Objects.equals(dataDir, packageInfo.getDeviceProtectedDataDirFile())) { |
| flags |= Context.CONTEXT_DEVICE_PROTECTED_STORAGE; |
| } |
| } |
| |
| mMainThread = mainThread; |
| mActivityToken = activityToken; |
| mFlags = flags; |
| |
| if (user == null) { |
| user = Process.myUserHandle(); |
| } |
| mUser = user; |
| |
| mPackageInfo = packageInfo; |
| mSplitName = splitName; |
| mClassLoader = classLoader; |
| mResourcesManager = ResourcesManager.getInstance(); |
| |
| if (container != null) { |
| mBasePackageName = container.mBasePackageName; |
| mOpPackageName = container.mOpPackageName; |
| setResources(container.mResources); |
| mDisplay = container.mDisplay; |
| } else { |
| mBasePackageName = packageInfo.mPackageName; |
| ApplicationInfo ainfo = packageInfo.getApplicationInfo(); |
| if (ainfo.uid == Process.SYSTEM_UID && ainfo.uid != Process.myUid()) { |
| // Special case: system components allow themselves to be loaded in to other |
| // processes. For purposes of app ops, we must then consider the context as |
| // belonging to the package of this process, not the system itself, otherwise |
| // the package+uid verifications in app ops will fail. |
| mOpPackageName = ActivityThread.currentPackageName(); |
| } else { |
| mOpPackageName = mBasePackageName; |
| } |
| } |
| |
| mContentResolver = new ApplicationContentResolver(this, mainThread); |
| } |
| |
| void setResources(Resources r) { |
| if (r instanceof CompatResources) { |
| ((CompatResources) r).setContext(this); |
| } |
| mResources = r; |
| } |
| |
| void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) { |
| mPackageInfo.installSystemApplicationInfo(info, classLoader); |
| } |
| |
| 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 setOuterContext(Context context) { |
| mOuterContext = context; |
| } |
| |
| final Context getOuterContext() { |
| return mOuterContext; |
| } |
| |
| @Override |
| public IBinder getActivityToken() { |
| return mActivityToken; |
| } |
| |
| private void checkMode(int mode) { |
| if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.N) { |
| if ((mode & MODE_WORLD_READABLE) != 0) { |
| throw new SecurityException("MODE_WORLD_READABLE no longer supported"); |
| } |
| if ((mode & MODE_WORLD_WRITEABLE) != 0) { |
| throw new SecurityException("MODE_WORLD_WRITEABLE no longer supported"); |
| } |
| } |
| } |
| |
| @SuppressWarnings("deprecation") |
| 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 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"); |
| } |
| |
| /** |
| * Ensure that given directories exist, trying to create them if missing. If |
| * unable to create, they are filtered by replacing with {@code null}. |
| */ |
| private File[] ensureExternalDirsExistOrFilter(File[] dirs) { |
| final StorageManager sm = getSystemService(StorageManager.class); |
| final File[] result = new File[dirs.length]; |
| for (int i = 0; i < dirs.length; i++) { |
| File dir = dirs[i]; |
| if (!dir.exists()) { |
| if (!dir.mkdirs()) { |
| // recheck existence in case of cross-process race |
| if (!dir.exists()) { |
| // Failing to mkdir() may be okay, since we might not have |
| // enough permissions; ask vold to create on our behalf. |
| try { |
| sm.mkdirs(dir); |
| } catch (Exception e) { |
| Log.w(TAG, "Failed to ensure " + dir + ": " + e); |
| dir = null; |
| } |
| } |
| } |
| } |
| result[i] = dir; |
| } |
| return result; |
| } |
| |
| // ---------------------------------------------------------------------- |
| // ---------------------------------------------------------------------- |
| // ---------------------------------------------------------------------- |
| |
| private static final class ApplicationContentResolver extends ContentResolver { |
| private final ActivityThread mMainThread; |
| |
| public ApplicationContentResolver(Context context, ActivityThread mainThread) { |
| super(context); |
| mMainThread = Preconditions.checkNotNull(mainThread); |
| } |
| |
| @Override |
| protected IContentProvider acquireProvider(Context context, String auth) { |
| return mMainThread.acquireProvider(context, |
| ContentProvider.getAuthorityWithoutUserId(auth), |
| resolveUserIdFromAuthority(auth), true); |
| } |
| |
| @Override |
| protected IContentProvider acquireExistingProvider(Context context, String auth) { |
| return mMainThread.acquireExistingProvider(context, |
| ContentProvider.getAuthorityWithoutUserId(auth), |
| resolveUserIdFromAuthority(auth), true); |
| } |
| |
| @Override |
| public boolean releaseProvider(IContentProvider provider) { |
| return mMainThread.releaseProvider(provider, true); |
| } |
| |
| @Override |
| protected IContentProvider acquireUnstableProvider(Context c, String auth) { |
| return mMainThread.acquireProvider(c, |
| ContentProvider.getAuthorityWithoutUserId(auth), |
| resolveUserIdFromAuthority(auth), false); |
| } |
| |
| @Override |
| public boolean releaseUnstableProvider(IContentProvider icp) { |
| return mMainThread.releaseProvider(icp, false); |
| } |
| |
| @Override |
| public void unstableProviderDied(IContentProvider icp) { |
| mMainThread.handleUnstableProviderDied(icp.asBinder(), true); |
| } |
| |
| @Override |
| public void appNotRespondingViaProvider(IContentProvider icp) { |
| mMainThread.appNotRespondingViaProvider(icp.asBinder()); |
| } |
| |
| /** @hide */ |
| protected int resolveUserIdFromAuthority(String auth) { |
| return ContentProvider.getUserIdFromAuthority(auth, getUserId()); |
| } |
| } |
| } |