summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorSvet Ganov <svetoslavganov@google.com>2021-03-30 20:43:33 +0000
committerSvetoslav Ganov <svetoslavganov@google.com>2021-03-31 02:11:46 +0000
commit7d058d62e5bfc2893e297ece9094665d628127c2 (patch)
treeff7f274617a7a2313979e1a7e709aeb562e4ce38 /core/java/android
parent6564529264063b185c93b033687ae900a332083d (diff)
Addressing comments from commit:8d2ed5
bug:158792096 bug:180647319 bug:184051153 bug:184027531 Test:atest CtsPermissionTestCases atest CtsPermission2TestCases atest CtsPermission3TestCases atest CtsPermission4TestCases atest CtsPermission5TestCases atest CtsAppOpsTestCases atest CtsAppOps2TestCases atest CtsAlarmManagerTestCases Change-Id: Id324ed0e2a653dface6ba273bba27e92bea14f99
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/AppOpsManager.java26
-rw-r--r--core/java/android/app/ContextImpl.java17
-rw-r--r--core/java/android/content/ContentResolver.java1
-rw-r--r--core/java/android/content/Context.java2
-rw-r--r--core/java/android/content/ContextParams.java14
-rw-r--r--core/java/android/content/PermissionChecker.java73
6 files changed, 79 insertions, 54 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index f76e1c0e50fb..6ce0b2283603 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7404,6 +7404,32 @@ public class AppOpsManager {
}
/**
+ * Resolves special UID's pakcages such as root, shell, media, etc.
+ *
+ * @param uid The uid to resolve.
+ * @param packageName Optional package. If caller system and null returns "android"
+ * @return The resolved package name.
+ *
+ * @hide
+ */
+ public static @Nullable String resolvePackageName(int uid, @Nullable String packageName) {
+ if (uid == Process.ROOT_UID) {
+ return "root";
+ } else if (uid == Process.SHELL_UID) {
+ return "com.android.shell";
+ } else if (uid == Process.MEDIA_UID) {
+ return "media";
+ } else if (uid == Process.AUDIOSERVER_UID) {
+ return "audioserver";
+ } else if (uid == Process.CAMERASERVER_UID) {
+ return "cameraserver";
+ } else if (uid == Process.SYSTEM_UID && packageName == null) {
+ return "android";
+ }
+ return packageName;
+ }
+
+ /**
* Monitor for changes to the operating mode for the given op in the given app package.
* You can watch op changes only for your UID.
*
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f8165e9a7cf6..eb31b5294a26 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -226,7 +226,7 @@ class ContextImpl extends Context {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final String mOpPackageName;
private final @NonNull ContextParams mParams;
- private @NonNull AttributionSource mAttributionSource;
+ private final @NonNull AttributionSource mAttributionSource;
private final @NonNull ResourcesManager mResourcesManager;
@UnsupportedAppUsage
@@ -3074,25 +3074,26 @@ class ContextImpl extends Context {
mOpPackageName = overrideOpPackageName != null ? overrideOpPackageName : opPackageName;
mParams = Objects.requireNonNull(params);
- initializeAttributionSource(attributionTag, nextAttributionSource);
+ mAttributionSource = createAttributionSource(attributionTag, nextAttributionSource);
mContentResolver = new ApplicationContentResolver(this, mainThread);
}
- private void initializeAttributionSource(@Nullable String attributionTag,
+ private @NonNull AttributionSource createAttributionSource(@Nullable String attributionTag,
@Nullable AttributionSource nextAttributionSource) {
- mAttributionSource = new AttributionSource(Process.myUid(), mOpPackageName,
+ AttributionSource attributionSource = new AttributionSource(Process.myUid(), mOpPackageName,
attributionTag, nextAttributionSource);
// If we want to access protected data on behalf of another app we need to
// tell the OS that we opt in to participate in the attribution chain.
if (nextAttributionSource != null) {
// If an app happened to stub the internal OS for testing the registration method
// can return null. In this case we keep the current untrusted attribution source.
- final AttributionSource attributionSource = getSystemService(PermissionManager.class)
- .registerAttributionSource(mAttributionSource);
- if (attributionSource != null) {
- mAttributionSource = attributionSource;
+ final AttributionSource registeredAttributionSource = getSystemService(
+ PermissionManager.class).registerAttributionSource(attributionSource);
+ if (registeredAttributionSource != null) {
+ return registeredAttributionSource;
}
}
+ return attributionSource;
}
void setResources(Resources r) {
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 14b2a65c4da6..aec39da973f0 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -3884,6 +3884,7 @@ public abstract class ContentResolver implements ContentInterface {
@UnsupportedAppUsage
private final Context mContext;
+ @Deprecated
@UnsupportedAppUsage
final String mPackageName;
final int mTargetSdkVersion;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8531d341ee9b..232daa8f8b47 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -6475,7 +6475,7 @@ public abstract class Context {
*/
@Deprecated
public @NonNull Context createFeatureContext(@Nullable String attributionTag) {
- return createContext(new ContextParams.Builder()
+ return createContext(new ContextParams.Builder(getParams())
.setAttributionTag(attributionTag)
.build());
}
diff --git a/core/java/android/content/ContextParams.java b/core/java/android/content/ContextParams.java
index 2b2db8fca2ca..bd3eaea24126 100644
--- a/core/java/android/content/ContextParams.java
+++ b/core/java/android/content/ContextParams.java
@@ -53,10 +53,11 @@ public final class ContextParams {
private ContextParams(@Nullable String attributionTag,
@Nullable AttributionSource next,
- @NonNull Set<String> renouncedPermissions) {
+ @Nullable Set<String> renouncedPermissions) {
mAttributionTag = attributionTag;
mNext = next;
- mRenouncedPermissions = renouncedPermissions;
+ mRenouncedPermissions = (renouncedPermissions != null)
+ ? renouncedPermissions : Collections.emptySet();
}
/**
@@ -149,8 +150,8 @@ public final class ContextParams {
* @see AttributionSource
*/
@NonNull
- public Builder setNextAttributionSource(@NonNull AttributionSource next) {
- mNext = Objects.requireNonNull(next);
+ public Builder setNextAttributionSource(@Nullable AttributionSource next) {
+ mNext = next;
return this;
}
@@ -177,9 +178,8 @@ public final class ContextParams {
@SystemApi
@RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
public @NonNull Builder setRenouncedPermissions(
- @NonNull Set<String> renouncedPermissions) {
- mRenouncedPermissions = Collections.unmodifiableSet(
- Objects.requireNonNull(renouncedPermissions));
+ @Nullable Set<String> renouncedPermissions) {
+ mRenouncedPermissions = renouncedPermissions;
return this;
}
diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java
index 08eac5aff655..6a254bd0465e 100644
--- a/core/java/android/content/PermissionChecker.java
+++ b/core/java/android/content/PermissionChecker.java
@@ -24,6 +24,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.os.Binder;
import android.os.Process;
+import android.util.Slog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -70,6 +71,8 @@ import java.util.concurrent.ConcurrentHashMap;
* @hide
*/
public final class PermissionChecker {
+ private static final String LOG_TAG = PermissionChecker.class.getName();
+
private static final String PLATFORM_PACKAGE_NAME = "android";
/** The permission is granted. */
@@ -92,6 +95,7 @@ public final class PermissionChecker {
/** Constant when the PID for which we check permissions is unknown. */
public static final int PID_UNKNOWN = -1;
+ // Cache for platform defined runtime permissions to avoid multi lookup (name -> info)
private static final ConcurrentHashMap<String, PermissionInfo> sPlatformPermissions
= new ConcurrentHashMap<>();
@@ -840,12 +844,11 @@ public final class PermissionChecker {
@NonNull AttributionSource attributionSource, @Nullable String message,
boolean forDataDelivery, boolean fromDatasource) {
final int op = AppOpsManager.permissionToOpCode(permission);
- if (op < 0 || attributionSource.getPackageName() == null) {
+ if (op < 0) {
+ Slog.wtf(LOG_TAG, "Appop permission " + permission + "with no app op defined:!");
return PERMISSION_HARD_DENIED;
}
- final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
-
AttributionSource current = attributionSource;
AttributionSource next = null;
@@ -856,28 +859,21 @@ public final class PermissionChecker {
// If the call is from a datasource we need to vet only the chain before it. This
// way we can avoid the datasource creating an attribution context for every call.
- if ((!fromDatasource || current != attributionSource)
+ if (!(fromDatasource && current == attributionSource)
&& next != null && !current.isTrusted(context)) {
return PERMISSION_HARD_DENIED;
}
- int opMode;
- if (forDataDelivery) {
- if (next == null) {
- opMode = appOpsManager.noteOpNoThrow(op, current.getUid(),
- current.getPackageName(), current.getAttributionTag(), message);
- } else {
- opMode = appOpsManager.noteProxyOpNoThrow(op, current, message,
- skipCurrentChecks);
- }
- } else {
- opMode = appOpsManager.unsafeCheckOpRawNoThrow(op, current.getUid(),
- current.getPackageName());
- if (next != null && opMode == AppOpsManager.MODE_ALLOWED) {
- opMode = appOpsManager.unsafeCheckOpRawNoThrow(op, next.getUid(),
- next.getPackageName());
- }
- }
+ // The access is for oneself if this is the single receiver of data
+ // after the data source or if this is the single attribution source
+ // in the chain if not from a datasource.
+ final boolean singleReceiverFromDatasource = (fromDatasource
+ && current == attributionSource && next != null && next.getNext() == null);
+ final boolean selfAccess = singleReceiverFromDatasource || next == null;
+
+ final int opMode = performOpTransaction(context, op, current, message,
+ forDataDelivery, /*startDataDelivery*/ false, skipCurrentChecks,
+ selfAccess, singleReceiverFromDatasource);
switch (opMode) {
case AppOpsManager.MODE_IGNORED:
@@ -920,7 +916,7 @@ public final class PermissionChecker {
// If the call is from a datasource we need to vet only the chain before it. This
// way we can avoid the datasource creating an attribution context for every call.
- if ((!fromDatasource || current != attributionSource)
+ if (!(fromDatasource && current == attributionSource)
&& next != null && !current.isTrusted(context)) {
return PERMISSION_HARD_DENIED;
}
@@ -937,6 +933,8 @@ public final class PermissionChecker {
}
if (op < 0) {
+ Slog.wtf(LOG_TAG, "Runtime permission " + permission + "with no app op defined:!");
+ current = next;
continue;
}
@@ -1021,7 +1019,7 @@ public final class PermissionChecker {
current = next;
}
}
- // If from data source and there is next app after that we need to note SELF of (noteOp) for the app vs proxy
+
private static int performOpTransaction(@NonNull Context context, int op,
@NonNull AttributionSource attributionSource, @Nullable String message,
boolean forDataDelivery, boolean startDataDelivery, boolean skipProxyOperation,
@@ -1031,27 +1029,26 @@ public final class PermissionChecker {
// do a best effort to resolve the package from the UID (pick first without a loss
// of generality - they are in the same security sandbox).
final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
+ final AttributionSource accessorSource = (!singleReceiverFromDatasource)
+ ? attributionSource : attributionSource.getNext();
if (!forDataDelivery) {
- final String resolvedPackageName = resolvePackageName(context, attributionSource);
- if (resolvedPackageName == null) {
+ final String resolvedAccessorPackageName = resolvePackageName(context, accessorSource);
+ if (resolvedAccessorPackageName == null) {
return AppOpsManager.MODE_ERRORED;
}
final int opMode = appOpsManager.unsafeCheckOpRawNoThrow(op,
- attributionSource.getUid(), resolvedPackageName);
- final AttributionSource previous = attributionSource.getNext();
- if (opMode == AppOpsManager.MODE_ALLOWED && previous != null) {
- final String resolvedPreviousPackageName = resolvePackageName(context,
- previous);
- if (resolvedPreviousPackageName == null) {
+ accessorSource.getUid(), resolvedAccessorPackageName);
+ final AttributionSource next = accessorSource.getNext();
+ if (!selfAccess && opMode == AppOpsManager.MODE_ALLOWED && next != null) {
+ final String resolvedNextPackageName = resolvePackageName(context, next);
+ if (resolvedNextPackageName == null) {
return AppOpsManager.MODE_ERRORED;
}
- return appOpsManager.unsafeCheckOpRawNoThrow(op, previous.getUid(),
- resolvedPreviousPackageName);
+ return appOpsManager.unsafeCheckOpRawNoThrow(op, next.getUid(),
+ resolvedNextPackageName);
}
return opMode;
} else if (startDataDelivery) {
- final AttributionSource accessorSource = (!singleReceiverFromDatasource)
- ? attributionSource : attributionSource.getNext();
final AttributionSource resolvedAttributionSource = resolveAttributionSource(
context, accessorSource);
if (resolvedAttributionSource.getPackageName() == null) {
@@ -1068,8 +1065,6 @@ public final class PermissionChecker {
skipProxyOperation);
}
} else {
- final AttributionSource accessorSource = (!singleReceiverFromDatasource)
- ? attributionSource : attributionSource.getNext();
final AttributionSource resolvedAttributionSource = resolveAttributionSource(
context, accessorSource);
if (resolvedAttributionSource.getPackageName() == null) {
@@ -1099,7 +1094,9 @@ public final class PermissionChecker {
// sandbox is UID, therefore we pick an arbitrary package.
return packageNames[0];
}
- return null;
+ // Last resort to handle special UIDs like root, etc.
+ return AppOpsManager.resolvePackageName(attributionSource.getUid(),
+ attributionSource.getPackageName());
}
private static @NonNull AttributionSource resolveAttributionSource(