Skip to content
This repository has been archived by the owner on Oct 29, 2024. It is now read-only.

Commit

Permalink
Support for getting the calling app's permission state for activities
Browse files Browse the repository at this point in the history
This allows for apps that can already access the calling app identity
that opens their activity, along with system browser, to check whenever
a permission is granted, similar to the permission entry in activity
section of AndroidManifest.xml.
  • Loading branch information
quh4gko8 committed Nov 17, 2023
1 parent ff2ba9f commit 427ce30
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 0 deletions.
13 changes: 13 additions & 0 deletions core/java/android/app/Activity.java
Original file line number Diff line number Diff line change
Expand Up @@ -6931,6 +6931,19 @@ public String getLaunchedFromPackage() {
return ActivityClient.getInstance().getLaunchedFromPackage(getActivityToken());
}

/**
* Returns if the permission is granted on app that initially launched this activity.
*
* <p>In order to receive the launching app's package name permission state,
* the current activity is from a system browser, otherwise {@code SecurityException} is thrown.
* @return the permission state of a permission if it's granted
* @hide
*/
@UnsupportedAppUsage
public int checkLaunchedFromPackagePermission(String permission) {
return ActivityClient.getInstance().checkLaunchedFromPackagePermission(getActivityToken(), permission);
}

/**
* Control whether this activity's main window is visible. This is intended
* only for the special case of an activity that is not going to show a
Expand Down
8 changes: 8 additions & 0 deletions core/java/android/app/ActivityClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,14 @@ public String getLaunchedFromPackage(IBinder token) {
}
}

public int checkLaunchedFromPackagePermission(IBinder token, String permission) {
try {
return getActivityClientController().checkLaunchedFromPackagePermission(token, permission);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

public void setRequestedOrientation(IBinder token, int requestedOrientation) {
try {
getActivityClientController().setRequestedOrientation(token, requestedOrientation);
Expand Down
7 changes: 7 additions & 0 deletions core/java/android/app/IActivityClientController.aidl
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,11 @@ interface IActivityClientController {
*/
boolean isRequestedToLaunchInTaskFragment(in IBinder activityToken,
in IBinder taskFragmentToken);

/**
* Return {@code true} if the calling package had a permission granted.
* Only accessible to system browser app and apps that can already access
* the app launching the activity via getLaunchedFrom{Uid,Package}
*/
int checkLaunchedFromPackagePermission(in IBinder token, String permission);
}
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,18 @@ public String getLaunchedFromPackage(IBinder token) {
return null;
}

@Override
public int checkLaunchedFromPackagePermission(IBinder token, String permission) {
if (!WindowManagerHooks.canAccessLaunchedFromPackagePermission()) {
throw new SecurityException();
}

synchronized (mGlobalLock) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
return WindowManagerHooks.checkLaunchedFromPackagePermission(r, permission);
}
}

/** Whether the call to one of the getLaunchedFrom APIs is performed by an internal caller. */
private boolean isInternalCallerGetLaunchedFrom(int uid) {
if (UserHandle.getAppId(uid) == SYSTEM_UID) {
Expand Down
77 changes: 77 additions & 0 deletions services/core/java/com/android/server/wm/WindowManagerHooks.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.android.server.wm;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.ext.BrowserUtils;
import android.os.Binder;
import android.os.Build;
import android.os.SystemProperties;
import android.os.UserHandle;

import com.android.internal.util.ArrayUtils;

import com.android.server.LocalServices;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;

class WindowManagerHooks {

static boolean canAccessLaunchedFromPackagePermission() {
final int callingUid = Binder.getCallingUid();
var pmi = LocalServices.getService(PackageManagerInternal.class);
AndroidPackage callingPkg = pmi.getPackage(callingUid);
if (callingPkg == null) {
return false;
}

String callingPkgName = callingPkg.getPackageName();
if (canAccessForDebuggingPurposes(callingPkgName)) {
return true;
}

Context ctx = ActivityThread.currentActivityThread().getSystemContext();
if (!BrowserUtils.isSystemBrowser(ctx, callingPkgName)) {
return false;
}

PackageStateInternal callingPsi = pmi.getPackageStateInternal(callingPkg.getPackageName());
if (callingPsi == null) {
return false;
}

return callingPsi.isSystem();
}

static boolean canAccessForDebuggingPurposes(@NonNull String packageName) {
if (!Build.isDebuggable()) {
return false;
}

String testPkgs = SystemProperties.get("persist.launchedFromPackagePermission_test_pkgs");
return ArrayUtils.contains(testPkgs.split(","), packageName);
}

static int checkLaunchedFromPackagePermission(@Nullable ActivityRecord r, @NonNull String permission) {
if (r == null) {
return PackageManager.PERMISSION_DENIED;
}

String packageName = r.launchedFromPackage;
final int userId = UserHandle.getUserId(r.launchedFromUid);
var permService = LocalServices.getService(PermissionManagerServiceInternal.class);

// Do not take into account of package visibility here.
long token = Binder.clearCallingIdentity();
try {
return permService.checkPermission(packageName, permission, userId);
} finally {
Binder.restoreCallingIdentity(token);
}

}
}

0 comments on commit 427ce30

Please sign in to comment.