Merge changes from topic "preserve_legacy"

* changes:
  Enforce the preserveLegacyExternalStorage manifest attribute
  Support preserveLegacyExternalStorage manifest attribute
  Introduce preserveLegacyExternalStorage manifest attribute
This commit is contained in:
Nandana Dutt
2020-02-15 21:59:23 +00:00
committed by Android (Google) Code Review
10 changed files with 134 additions and 3 deletions

View File

@@ -1082,6 +1082,7 @@ package android {
field public static final int preferenceScreenStyle = 16842891; // 0x101008b
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int preserveLegacyExternalStorage = 16844312; // 0x1010618
field public static final int previewImage = 16843482; // 0x10102da
field public static final int primaryContentAlpha = 16844114; // 0x1010552
field public static final int priority = 16842780; // 0x101001c

View File

@@ -397,6 +397,8 @@ public interface AndroidPackage extends Parcelable {
boolean hasComponentClassName(String className);
boolean hasPreserveLegacyExternalStorage();
// App Info
boolean hasRequestedLegacyExternalStorage();

View File

@@ -2101,6 +2101,10 @@ public class ApkParseUtils {
parsingPackage.setAllowNativeHeapPointerTagging(sa.getBoolean(
R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, true));
parsingPackage.setPreserveLegacyExternalStorage(sa.getBoolean(
R.styleable.AndroidManifestApplication_preserveLegacyExternalStorage,
false));
parsingPackage
.setMaxAspectRatio(
sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0))

View File

@@ -289,6 +289,7 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
private String[] usesLibraryFiles;
private List<SharedLibraryInfo> usesLibraryInfos;
private String zygotePreloadName;
private boolean preserveLegacyExternalStorage;
@VisibleForTesting
public PackageImpl(
@@ -1518,6 +1519,12 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
return this;
}
@Override
public PackageImpl setPreserveLegacyExternalStorage(boolean preserveLegacyExternalStorage) {
this.preserveLegacyExternalStorage = preserveLegacyExternalStorage;
return this;
}
@Override
public PackageImpl setUsesNonSdkApi(boolean usesNonSdkApi) {
this.privateFlags = usesNonSdkApi
@@ -2999,6 +3006,11 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
return queriesProviders;
}
@Override
public boolean hasPreserveLegacyExternalStorage() {
return preserveLegacyExternalStorage;
}
private static void internStringArrayList(List<String> list) {
if (list != null) {
final int N = list.size();

View File

@@ -192,6 +192,8 @@ public interface ParsingPackage extends AndroidPackage {
ParsingPackage setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage);
ParsingPackage setAllowNativeHeapPointerTagging(boolean allowNativeHeapPointerTagging);
ParsingPackage setPreserveLegacyExternalStorage(boolean preserveLegacyExternalStorage);
ParsingPackage setRestoreAnyVersion(boolean restoreAnyVersion);

View File

@@ -118,4 +118,10 @@ public abstract class StorageManagerInternal {
* @param userId the userId for which to reset storage
*/
public abstract void resetUser(int userId);
/**
* Returns {@code true} if the immediate last installed version of an app with {@code uid} had
* legacy storage, {@code false} otherwise.
*/
public abstract boolean hasLegacyExternalStorage(int uid);
}

View File

@@ -1770,6 +1770,21 @@
-->
<attr name="requestLegacyExternalStorage" format="boolean" />
<!-- If {@code true} this app would like to preserve the legacy storage
model from a previously installed version. Note that this may not always be
respected due to policy or backwards compatibility reasons.
<p>This has no effect on the first install of an app on a device.
For an updating app, setting this to {@code true} will preserve the legacy behaviour
configured by the {@code requestLegacyExternalStorage} flag. If on an update, this
flag is set to {@code false} then the legacy access is not preserved, such an app can
only have legacy access with the {@code requestLegacyExternalStorage} flag.
<p>
The default value is {@code false}.
-->
<attr name="preserveLegacyExternalStorage" format="boolean" />
<!-- If {@code true} this app declares that it should be visible to all other apps on
device, regardless of what they declare via the {@code queries} tags in their
manifest.

View File

@@ -3018,6 +3018,7 @@
<!-- @hide @SystemApi -->
<public name="isAutofillInlineSuggestionTheme" />
<public name="allowNativeHeapPointerTagging" />
<public name="preserveLegacyExternalStorage" />
</public-group>
<public-group type="drawable" first-id="0x010800b5">

View File

@@ -28,6 +28,10 @@ import static android.app.AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED;
@@ -136,6 +140,7 @@ import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.AppFuseMount;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.FuseUnavailableMountException;
@@ -149,6 +154,7 @@ import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.SystemService.TargetUser;
import com.android.server.pm.Installer;
import com.android.server.storage.AppFuseBridge;
import com.android.server.storage.StorageSessionController;
@@ -184,6 +190,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -270,6 +277,11 @@ class StorageManagerService extends IStorageManager.Stub
public void onStopUser(int userHandle) {
mStorageManagerService.onStopUser(userHandle);
}
@Override
public void onStartUser(TargetUser user) {
mStorageManagerService.snapshotAndMonitorLegacyStorageAppOp(user.getUserHandle());
}
}
private static final boolean DEBUG_EVENTS = false;
@@ -578,6 +590,12 @@ class StorageManagerService extends IStorageManager.Stub
private final boolean mIsFuseEnabled;
@GuardedBy("mLock")
private final Set<Integer> mUidsWithLegacyExternalStorage = new ArraySet<>();
// Not guarded by lock, always used on the ActivityManager thread
private final Map<Integer, PackageMonitor> mPackageMonitorsForUser = new ArrayMap<>();
class ObbState implements IBinder.DeathRecipient {
public ObbState(String rawPath, String canonicalPath, int callingUid,
IObbActionListener token, int nonce, String volId) {
@@ -1145,6 +1163,10 @@ class StorageManagerService extends IStorageManager.Stub
} catch (Exception e) {
Slog.wtf(TAG, e);
}
PackageMonitor monitor = mPackageMonitorsForUser.remove(userId);
if (monitor != null) {
monitor.unregister();
}
}
private boolean supportsBlockCheckpoint() throws RemoteException {
@@ -1836,6 +1858,49 @@ class StorageManagerService extends IStorageManager.Stub
}
}
private void updateLegacyStorageApps(String packageName, int uid, boolean hasLegacy) {
synchronized (mLock) {
if (hasLegacy) {
Slog.v(TAG, "Package " + packageName + " has legacy storage");
mUidsWithLegacyExternalStorage.add(uid);
} else {
// TODO(b/149391976): Handle shared user id. Check if there's any other
// installed app with legacy external storage before removing
Slog.v(TAG, "Package " + packageName + " does not have legacy storage");
mUidsWithLegacyExternalStorage.remove(uid);
}
}
}
private void snapshotAndMonitorLegacyStorageAppOp(UserHandle user) {
int userId = user.getIdentifier();
// TODO(b/149391976): Use mIAppOpsService.getPackagesForOps instead of iterating below
// It should improve performance but the AppOps method doesn't return any app here :(
// This operation currently takes about ~20ms on a freshly flashed device
for (ApplicationInfo ai : mPmInternal.getInstalledApplications(MATCH_DIRECT_BOOT_AWARE
| MATCH_DIRECT_BOOT_UNAWARE | MATCH_UNINSTALLED_PACKAGES | MATCH_ANY_USER,
userId, Process.myUid())) {
try {
boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE, ai.uid,
ai.packageName) == MODE_ALLOWED;
updateLegacyStorageApps(ai.packageName, ai.uid, hasLegacy);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to check legacy op for package " + ai.packageName, e);
}
}
PackageMonitor monitor = new PackageMonitor() {
@Override
public void onPackageRemoved(String packageName, int uid) {
updateLegacyStorageApps(packageName, uid, false);
}
};
// TODO(b/149391976): Use different handler?
monitor.register(mContext, user, true, mHandler);
mPackageMonitorsForUser.put(userId, monitor);
}
private static long getLastAccessTime(AppOpsManager manager,
int uid, String packageName, int[] ops) {
long maxTime = 0;
@@ -4337,6 +4402,13 @@ class StorageManagerService extends IStorageManager.Stub
mHandler.obtainMessage(H_RESET).sendToTarget();
}
@Override
public boolean hasLegacyExternalStorage(int uid) {
synchronized (mLock) {
return mUidsWithLegacyExternalStorage.contains(uid);
}
}
public boolean hasExternalStorage(int uid, String packageName) {
// No need to check for system uid. This avoids a deadlock between
// PackageManagerService and AppOpsService.
@@ -4382,8 +4454,11 @@ class StorageManagerService extends IStorageManager.Stub
// volumes, USB OTGs that are rarely mounted. The app will get the
// external_storage gid on next organic restart.
killAppForOpChange(code, uid, packageName);
return;
}
return;
case OP_LEGACY_STORAGE:
updateLegacyStorageApps(packageName, uid, mode == MODE_ALLOWED);
return;
}
}

View File

@@ -35,14 +35,17 @@ import android.compat.annotation.EnabledAfter;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.storage.StorageManagerInternal;
import android.util.Log;
import com.android.internal.compat.IPlatformCompat;
import com.android.server.LocalServices;
/**
* The behavior of soft restricted permissions is different for each permission. This class collects
@@ -107,11 +110,16 @@ public abstract class SoftRestrictedPermissionPolicy {
final boolean isWhiteListed;
boolean shouldApplyRestriction;
final boolean hasRequestedLegacyExternalStorage;
final boolean shouldPreserveLegacyExternalStorage;
final boolean hasWriteMediaStorageGrantedForUid;
final boolean isScopedStorageEnabled;
if (appInfo != null) {
PackageManager pm = context.getPackageManager();
PackageManagerInternal pmInternal =
LocalServices.getService(PackageManagerInternal.class);
StorageManagerInternal smInternal =
LocalServices.getService(StorageManagerInternal.class);
int flags = pm.getPermissionFlags(permission, appInfo.packageName, user);
isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
hasRequestedLegacyExternalStorage = hasUidRequestedLegacyExternalStorage(
@@ -123,12 +131,16 @@ public abstract class SoftRestrictedPermissionPolicy {
isScopedStorageEnabled =
isChangeEnabledForUid(context, appInfo, user, ENABLE_SCOPED_STORAGE)
|| isScopedStorageRequired;
shouldPreserveLegacyExternalStorage = pmInternal.getPackage(
appInfo.packageName).hasPreserveLegacyExternalStorage()
&& smInternal.hasLegacyExternalStorage(appInfo.uid);
shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0
|| isScopedStorageRequired;
|| (isScopedStorageRequired && !shouldPreserveLegacyExternalStorage);
} else {
isWhiteListed = false;
shouldApplyRestriction = false;
hasRequestedLegacyExternalStorage = false;
shouldPreserveLegacyExternalStorage = false;
hasWriteMediaStorageGrantedForUid = false;
isScopedStorageEnabled = false;
}
@@ -150,7 +162,8 @@ public abstract class SoftRestrictedPermissionPolicy {
public boolean mayAllowExtraAppOp() {
return !shouldApplyRestriction
&& (hasRequestedLegacyExternalStorage
|| hasWriteMediaStorageGrantedForUid);
|| hasWriteMediaStorageGrantedForUid
|| shouldPreserveLegacyExternalStorage);
}
@Override
public boolean mayDenyExtraAppOpIfGranted() {