Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8da0f1e2 authored by Shai Barack's avatar Shai Barack
Browse files

Reduce lock contention in ContextImpl

Use double-check pattern.
Don't use same lock for dir creation work and for resources work.

Bug: 259323318
Change-Id: I4da7e00f1e87d15bb22701a602beeae965b61a32
parent 053fd082
Loading
Loading
Loading
Loading
+156 −75
Original line number Diff line number Diff line
@@ -272,10 +272,17 @@ class ContextImpl extends Context {

    @UnsupportedAppUsage
    private Context mOuterContext;

    private final Object mThemeLock = new Object();

    @UnsupportedAppUsage
    @GuardedBy("mThemeLock")
    private int mThemeResource = 0;

    @UnsupportedAppUsage
    @GuardedBy("mThemeLock")
    private Resources.Theme mTheme = null;

    @UnsupportedAppUsage
    private PackageManager mPackageManager;
    private Context mReceiverRestrictedContext = null;
@@ -288,7 +295,6 @@ class ContextImpl extends Context {

    private ContentCaptureOptions mContentCaptureOptions = null;

    private final Object mSync = new Object();
    /**
     * Indicates this {@link Context} can not handle UI components properly and is not associated
     * with a {@link Display} instance.
@@ -340,21 +346,18 @@ class ContextImpl extends Context {
     */
    private boolean mOwnsToken = false;

    @GuardedBy("mSync")
    private File mDatabasesDir;
    @GuardedBy("mSync")
    @UnsupportedAppUsage
    private File mPreferencesDir;
    @GuardedBy("mSync")
    private File mFilesDir;
    @GuardedBy("mSync")
    private File mCratesDir;
    @GuardedBy("mSync")
    private File mNoBackupFilesDir;
    @GuardedBy("mSync")
    private File mCacheDir;
    @GuardedBy("mSync")
    private File mCodeCacheDir;
    private final Object mDirsLock = new Object();
    private volatile File mDatabasesDir;
    @UnsupportedAppUsage private volatile File mPreferencesDir;
    private volatile File mFilesDir;
    private volatile File mCratesDir;
    private volatile File mNoBackupFilesDir;
    private volatile File[] mExternalFilesDirs;
    private volatile File[] mObbDirs;
    private volatile File mCacheDir;
    private volatile File mCodeCacheDir;
    private volatile File[] mExternalCacheDirs;
    private volatile File[] mExternalMediaDirs;

    // The system service cache for the system services that are cached per-ContextImpl.
    @UnsupportedAppUsage
@@ -458,7 +461,7 @@ class ContextImpl extends Context {

    @Override
    public void setTheme(int resId) {
        synchronized (mSync) {
        synchronized (mThemeLock) {
            if (mThemeResource != resId) {
                mThemeResource = resId;
                initializeTheme();
@@ -468,14 +471,14 @@ class ContextImpl extends Context {

    @Override
    public int getThemeResId() {
        synchronized (mSync) {
        synchronized (mThemeLock) {
            return mThemeResource;
        }
    }

    @Override
    public Resources.Theme getTheme() {
        synchronized (mSync) {
        synchronized (mThemeLock) {
            if (mTheme != null) {
                return mTheme;
            }
@@ -488,6 +491,7 @@ class ContextImpl extends Context {
        }
    }

    @GuardedBy("mThemeLock")
    private void initializeTheme() {
        if (mTheme == null) {
            mTheme = mResources.newTheme();
@@ -731,12 +735,18 @@ class ContextImpl extends Context {

    @UnsupportedAppUsage
    private File getPreferencesDir() {
        synchronized (mSync) {
            if (mPreferencesDir == null) {
                mPreferencesDir = new File(getDataDir(), "shared_prefs");
        File localPreferencesDir = mPreferencesDir;
        if (localPreferencesDir == null) {
            synchronized (mDirsLock) {
                localPreferencesDir = mPreferencesDir;
                if (localPreferencesDir == null) {
                    localPreferencesDir = new File(getDataDir(), "shared_prefs");
                    ensurePrivateDirExists(localPreferencesDir);
                    mPreferencesDir = localPreferencesDir;
                }
            }
            return ensurePrivateDirExists(mPreferencesDir);
        }
        return localPreferencesDir;
    }

    @Override
@@ -778,16 +788,16 @@ class ContextImpl extends Context {
    /**
     * Common-path handling of app data dir creation
     */
    private static File ensurePrivateDirExists(File file) {
        return ensurePrivateDirExists(file, 0771, -1, null);
    private static void ensurePrivateDirExists(File file) {
        ensurePrivateDirExists(file, 0771, -1, null);
    }

    private static File ensurePrivateCacheDirExists(File file, String xattr) {
    private static void ensurePrivateCacheDirExists(File file, String xattr) {
        final int gid = UserHandle.getCacheAppGid(Process.myUid());
        return ensurePrivateDirExists(file, 02771, gid, xattr);
        ensurePrivateDirExists(file, 02771, gid, xattr);
    }

    private static File ensurePrivateDirExists(File file, int mode, int gid, String xattr) {
    private static void ensurePrivateDirExists(File file, int mode, int gid, String xattr) {
        if (!file.exists()) {
            final String path = file.getAbsolutePath();
            try {
@@ -815,17 +825,22 @@ class ContextImpl extends Context {
                }
            }
        }
        return file;
    }

    @Override
    public File getFilesDir() {
        synchronized (mSync) {
            if (mFilesDir == null) {
                mFilesDir = new File(getDataDir(), "files");
        File localFilesDir = mFilesDir;
        if (localFilesDir == null) {
            localFilesDir = mFilesDir;
            synchronized (mDirsLock) {
                if (localFilesDir == null) {
                    localFilesDir = new File(getDataDir(), "files");
                    ensurePrivateDirExists(localFilesDir);
                    mFilesDir = localFilesDir;
                }
            }
            return ensurePrivateDirExists(mFilesDir);
        }
        return localFilesDir;
    }

    @Override
@@ -835,26 +850,38 @@ class ContextImpl extends Context {
        final Path absoluteNormalizedCratePath = cratesRootPath.resolve(crateId)
                .toAbsolutePath().normalize();

        synchronized (mSync) {
            if (mCratesDir == null) {
                mCratesDir = cratesRootPath.toFile();
        File localCratesDir = mCratesDir;
        if (localCratesDir == null) {
            synchronized (mDirsLock) {
                localCratesDir = mCratesDir;
                if (localCratesDir == null) {
                    localCratesDir = cratesRootPath.toFile();
                    ensurePrivateDirExists(localCratesDir);
                    mCratesDir = localCratesDir;
                }
            }
            ensurePrivateDirExists(mCratesDir);
        }

        File cratedDir = absoluteNormalizedCratePath.toFile();
        return ensurePrivateDirExists(cratedDir);
        File crateDir = absoluteNormalizedCratePath.toFile();
        ensurePrivateDirExists(crateDir);
        return crateDir;
    }

    @Override
    public File getNoBackupFilesDir() {
        synchronized (mSync) {
            if (mNoBackupFilesDir == null) {
                mNoBackupFilesDir = new File(getDataDir(), "no_backup");
        File localNoBackupFilesDir = mNoBackupFilesDir;
        if (localNoBackupFilesDir == null) {
            synchronized (mDirsLock) {
                localNoBackupFilesDir = mNoBackupFilesDir;
                if (localNoBackupFilesDir == null) {
                    localNoBackupFilesDir = new File(getDataDir(), "no_backup");
                    ensurePrivateDirExists(localNoBackupFilesDir);
                    mNoBackupFilesDir = localNoBackupFilesDir;
                }
            return ensurePrivateDirExists(mNoBackupFilesDir);
            }
        }
        return localNoBackupFilesDir;
    }

    @Override
    public File getExternalFilesDir(String type) {
@@ -865,14 +892,25 @@ class ContextImpl extends Context {

    @Override
    public File[] getExternalFilesDirs(String type) {
        synchronized (mSync) {
            File[] dirs = Environment.buildExternalStorageAppFilesDirs(getPackageName());
        File[] localExternalFilesDirs = mExternalFilesDirs;
        if (localExternalFilesDirs == null) {
            synchronized (mDirsLock) {
                localExternalFilesDirs = mExternalFilesDirs;
                if (localExternalFilesDirs == null) {
                    localExternalFilesDirs =
                            Environment.buildExternalStorageAppFilesDirs(getPackageName());
                    if (type != null) {
                dirs = Environment.buildPaths(dirs, type);
                        localExternalFilesDirs =
                                Environment.buildPaths(localExternalFilesDirs, type);
                    }
                    localExternalFilesDirs = ensureExternalDirsExistOrFilter(
                            localExternalFilesDirs, true /* tryCreateInProcess */);
                    mExternalFilesDirs = localExternalFilesDirs;
                }
            return ensureExternalDirsExistOrFilter(dirs, true /* tryCreateInProcess */);
            }
        }
        return localExternalFilesDirs;
    }

    @Override
    public File getObbDir() {
@@ -883,30 +921,51 @@ class ContextImpl extends Context {

    @Override
    public File[] getObbDirs() {
        synchronized (mSync) {
            File[] dirs = Environment.buildExternalStorageAppObbDirs(getPackageName());
            return ensureExternalDirsExistOrFilter(dirs, true /* tryCreateInProcess */);
        File[] localObbDirs = mObbDirs;
        if (mObbDirs == null) {
            synchronized (mDirsLock) {
                localObbDirs = mObbDirs;
                if (localObbDirs == null) {
                    localObbDirs = Environment.buildExternalStorageAppObbDirs(getPackageName());
                    localObbDirs = ensureExternalDirsExistOrFilter(
                            localObbDirs, true /* tryCreateInProcess */);
                    mObbDirs = localObbDirs;
                }
            }
        }
        return localObbDirs;
    }

    @Override
    public File getCacheDir() {
        synchronized (mSync) {
            if (mCacheDir == null) {
                mCacheDir = new File(getDataDir(), "cache");
        File localCacheDir = mCacheDir;
        if (localCacheDir == null) {
            synchronized (mDirsLock) {
                localCacheDir = mCacheDir;
                if (localCacheDir == null) {
                    localCacheDir = new File(getDataDir(), "cache");
                    ensurePrivateCacheDirExists(localCacheDir, XATTR_INODE_CACHE);
                    mCacheDir = localCacheDir;
                }
            return ensurePrivateCacheDirExists(mCacheDir, XATTR_INODE_CACHE);
            }
        }
        return localCacheDir;
    }

    @Override
    public File getCodeCacheDir() {
        synchronized (mSync) {
            if (mCodeCacheDir == null) {
                mCodeCacheDir = getCodeCacheDirBeforeBind(getDataDir());
        File localCodeCacheDir = mCodeCacheDir;
        if (localCodeCacheDir == null) {
            synchronized (mDirsLock) {
                localCodeCacheDir = mCodeCacheDir;
                if (localCodeCacheDir == null) {
                    localCodeCacheDir = getCodeCacheDirBeforeBind(getDataDir());
                    ensurePrivateCacheDirExists(localCodeCacheDir, XATTR_INODE_CODE_CACHE);
                    mCodeCacheDir = localCodeCacheDir;
                }
            }
            return ensurePrivateCacheDirExists(mCodeCacheDir, XATTR_INODE_CODE_CACHE);
        }
        return localCodeCacheDir;
    }

    /**
@@ -927,22 +986,38 @@ class ContextImpl extends Context {

    @Override
    public File[] getExternalCacheDirs() {
        synchronized (mSync) {
            File[] dirs = Environment.buildExternalStorageAppCacheDirs(getPackageName());
            // We don't try to create cache directories in-process, because they need special
            // setup for accurate quota tracking. This ensures the cache dirs are always
            // created through StorageManagerService.
            return ensureExternalDirsExistOrFilter(dirs, false /* tryCreateInProcess */);
        File[] localExternalCacheDirs = mExternalCacheDirs;
        if (localExternalCacheDirs == null) {
            synchronized (mDirsLock) {
                localExternalCacheDirs = mExternalCacheDirs;
                if (localExternalCacheDirs == null) {
                    localExternalCacheDirs =
                            Environment.buildExternalStorageAppCacheDirs(getPackageName());
                    localExternalCacheDirs = ensureExternalDirsExistOrFilter(
                            localExternalCacheDirs, false /* tryCreateInProcess */);
                    mExternalCacheDirs = localExternalCacheDirs;
                }
            }
        }
        return localExternalCacheDirs;
    }

    @Override
    public File[] getExternalMediaDirs() {
        synchronized (mSync) {
            File[] dirs = Environment.buildExternalStorageAppMediaDirs(getPackageName());
            return ensureExternalDirsExistOrFilter(dirs, true /* tryCreateInProcess */);
        File[] localExternalMediaDirs = mExternalMediaDirs;
        if (localExternalMediaDirs == null) {
            synchronized (mDirsLock) {
                localExternalMediaDirs = mExternalMediaDirs;
                if (localExternalMediaDirs == null) {
                    localExternalMediaDirs = Environment.buildExternalStorageAppMediaDirs(getPackageName());
                    localExternalMediaDirs = ensureExternalDirsExistOrFilter(
                            localExternalMediaDirs, true /* tryCreateInProcess */);
                    mExternalMediaDirs = localExternalMediaDirs;
                }
            }
        }
        return localExternalMediaDirs;
    }

    /**
     * @hide
@@ -1040,16 +1115,22 @@ class ContextImpl extends Context {
    }

    private File getDatabasesDir() {
        synchronized (mSync) {
            if (mDatabasesDir == null) {
        File localDatabasesDir = mDatabasesDir;
        if (localDatabasesDir == null) {
            synchronized (mDirsLock) {
                localDatabasesDir = mDatabasesDir;
                if (localDatabasesDir == null) {
                    if ("android".equals(getPackageName())) {
                    mDatabasesDir = new File("/data/system");
                        localDatabasesDir = new File("/data/system");
                    } else {
                    mDatabasesDir = new File(getDataDir(), "databases");
                        localDatabasesDir = new File(getDataDir(), "databases");
                    }
                    ensurePrivateDirExists(localDatabasesDir);
                    mDatabasesDir = localDatabasesDir;
                }
            }
            return ensurePrivateDirExists(mDatabasesDir);
        }
        return localDatabasesDir;
    }

    @Override