diff options
5 files changed, 43 insertions, 11 deletions
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java index a1357c91b2cf..bde562dbf95b 100644 --- a/core/java/android/content/AttributionSource.java +++ b/core/java/android/content/AttributionSource.java @@ -231,7 +231,7 @@ public final class AttributionSource implements Parcelable { } /** @hide */ - public AttributionSource withToken(@NonNull Binder token) { + public AttributionSource withToken(@NonNull IBinder token) { return new AttributionSource(getUid(), getPid(), getPackageName(), getAttributionTag(), token, mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext()); } diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl index 7cecfdca851a..471f95bb21f3 100644 --- a/core/java/android/permission/IPermissionManager.aidl +++ b/core/java/android/permission/IPermissionManager.aidl @@ -92,7 +92,7 @@ interface IPermissionManager { boolean isAutoRevokeExempted(String packageName, int userId); - void registerAttributionSource(in AttributionSourceState source); + IBinder registerAttributionSource(in AttributionSourceState source); boolean isRegisteredAttributionSource(in AttributionSourceState source); diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 91adc37cb654..4af6e3a9f8d4 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -23,6 +23,7 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; import static android.os.Build.VERSION_CODES.S; +import static android.permission.flags.Flags.serverSideAttributionRegistration; import android.Manifest; import android.annotation.CheckResult; @@ -59,6 +60,7 @@ import android.media.AudioManager; import android.os.Binder; import android.os.Build; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Process; @@ -1464,13 +1466,19 @@ public final class PermissionManager { // We use a shared static token for sources that are not registered since the token's // only used for process death detection. If we are about to use the source for security // enforcement we need to replace the binder with a unique one. - final AttributionSource registeredSource = source.withToken(new Binder()); try { - mPermissionManager.registerAttributionSource(registeredSource.asState()); + if (serverSideAttributionRegistration()) { + IBinder newToken = mPermissionManager.registerAttributionSource(source.asState()); + return source.withToken(newToken); + } else { + AttributionSource registeredSource = source.withToken(new Binder()); + mPermissionManager.registerAttributionSource(registeredSource.asState()); + return registeredSource; + } } catch (RemoteException e) { e.rethrowFromSystemServer(); } - return registeredSource; + return source; } /** diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index 60143cc79d2d..bced21730a34 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -73,6 +73,13 @@ flag { } flag { + name: "server_side_attribution_registration" + namespace: "permissions" + description: "controls whether the binder representing an AttributionSource is created in the system server, or client process" + bug: "310953959" +} + +flag { name: "wallet_role_enabled" namespace: "wallet_integration" description: "This flag is used to enabled the Wallet Role for all users on the device" diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 5d710d272fc9..ee40e18b7d9f 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -29,6 +29,7 @@ import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.AppOpsManager.OP_BLUETOOTH_CONNECT; import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISALLOWED; import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISCOURAGED; +import static android.permission.flags.Flags.serverSideAttributionRegistration; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; @@ -439,10 +440,27 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } + /** + * Reference propagation over binder is affected by the ownership of the object. So if + * the token is owned by client, references to the token on client side won't be + * propagated to the server and the token may still be garbage collected on server side. + * But if the token is owned by server, references to the token on client side will now + * be propagated to the server since it's a foreign object to the client, and that will + * keep the token referenced on the server side as long as the client is alive and + * holding it. + */ @Override - public void registerAttributionSource(@NonNull AttributionSourceState source) { - mAttributionSourceRegistry - .registerAttributionSource(new AttributionSource(source)); + public IBinder registerAttributionSource(@NonNull AttributionSourceState source) { + if (serverSideAttributionRegistration()) { + Binder token = new Binder(); + mAttributionSourceRegistry + .registerAttributionSource(new AttributionSource(source).withToken(token)); + return token; + } else { + mAttributionSourceRegistry + .registerAttributionSource(new AttributionSource(source)); + return source.token; + } } @Override @@ -1218,7 +1236,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { @Nullable String message, boolean forDataDelivery, boolean startDataDelivery, boolean fromDatasource, int attributedOp) { PermissionInfo permissionInfo = sPlatformPermissions.get(permission); - if (permissionInfo == null) { try { permissionInfo = context.getPackageManager().getPermissionInfo(permission, 0); @@ -1346,8 +1363,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { // 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.equals(attributionSource)) - && next != null && !current.isTrusted(context)) { + boolean isDatasource = fromDatasource && current.equals(attributionSource); + if (!isDatasource && next != null && !current.isTrusted(context)) { return PermissionChecker.PERMISSION_HARD_DENIED; } |