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

Commit 60d85a42 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Use compat flags to reflect the current status of legacy storage." into...

Merge "Use compat flags to reflect the current status of legacy storage." into rvc-dev am: 6838c0ef

Change-Id: I6b6b543b90b98dd2f7ec82587d116c7ae812665d
parents 88502ffd 6838c0ef
Loading
Loading
Loading
Loading
+42 −20
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.annotation.TestApi;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.compat.Compatibility;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
@@ -88,6 +89,16 @@ public class Environment {
    private static final File DIR_APEX_ROOT = getDirectory(ENV_APEX_ROOT,
            "/apex");

    /**
     * See definition in com.android.providers.media.LocalCallingIdentity
     */
    private static final long DEFAULT_SCOPED_STORAGE = 149924527L;

    /**
     * See definition in com.android.providers.media.LocalCallingIdentity
     */
    private static final long FORCE_ENABLE_SCOPED_STORAGE = 132649864L;

    @UnsupportedAppUsage
    private static UserEnvironment sCurrentUser;
    private static boolean sUserRequired;
@@ -1191,12 +1202,13 @@ public class Environment {
    }

    /**
     * Returns whether the primary shared/external storage media is a legacy
     * view that includes files not owned by the app.
     * Returns whether the shared/external storage media is a
     * legacy view that includes files not owned by the app.
     * <p>
     * This value may be different from the value requested by
     * {@code requestLegacyExternalStorage} in the app's manifest, since an app
     * may inherit its legacy state based on when it was first installed.
     * may inherit its legacy state based on when it was first installed, target sdk and other
     * factors.
     * <p>
     * Non-legacy apps can continue to discover and read media belonging to
     * other apps via {@link android.provider.MediaStore}.
@@ -1207,12 +1219,13 @@ public class Environment {
    }

    /**
     * Returns whether the shared/external storage media at the given path is a
     * Returns whether the shared/external storage media is a
     * legacy view that includes files not owned by the app.
     * <p>
     * This value may be different from the value requested by
     * {@code requestLegacyExternalStorage} in the app's manifest, since an app
     * may inherit its legacy state based on when it was first installed.
     * may inherit its legacy state based on when it was first installed, target sdk and other
     * factors.
     * <p>
     * Non-legacy apps can continue to discover and read media belonging to
     * other apps via {@link android.provider.MediaStore}.
@@ -1232,24 +1245,23 @@ public class Environment {
            return false;
        }

        if (packageManager.checkPermission(Manifest.permission.WRITE_MEDIA_STORAGE,
                context.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
            return true;
        }

        if (packageManager.checkPermission(Manifest.permission.INSTALL_PACKAGES,
                context.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
            return true;
        // TODO(b/150672994): Compat flags do not override instant app and isolated process's
        //  behavior.
        boolean defaultScopedStorage = Compatibility.isChangeEnabled(DEFAULT_SCOPED_STORAGE);
        boolean forceEnableScopedStorage = Compatibility.isChangeEnabled(
                FORCE_ENABLE_SCOPED_STORAGE);
        // if Scoped Storage is strictly enforced, the app does *not* have legacy storage access
        // Note: does not require packagename/uid as this is directly called from an app process
        if (isScopedStorageEnforced(defaultScopedStorage, forceEnableScopedStorage)) {
            return false;
        }
        final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
        final String[] packagesForUid = packageManager.getPackagesForUid(uid);
        for (String packageName : packagesForUid) {
            if (appOps.checkOpNoThrow(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
                    uid, packageName) == AppOpsManager.MODE_ALLOWED) {
        // if Scoped Storage is strictly disabled, the app has legacy storage access
        // Note: does not require packagename/uid as this is directly called from an app process
        if (isScopedStorageDisabled(defaultScopedStorage, forceEnableScopedStorage)) {
            return true;
        }
        }

        final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
        return appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
                uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
    }
@@ -1298,6 +1310,16 @@ public class Environment {
        }
    }

    private static boolean isScopedStorageEnforced(boolean defaultScopedStorage,
            boolean forceEnableScopedStorage) {
        return defaultScopedStorage && forceEnableScopedStorage;
    }

    private static boolean isScopedStorageDisabled(boolean defaultScopedStorage,
            boolean forceEnableScopedStorage) {
        return !defaultScopedStorage && !forceEnableScopedStorage;
    }

    static File getDirectory(String variableName, String defaultPath) {
        String path = System.getenv(variableName);
        return path == null ? new File(defaultPath) : new File(path);