From 244c892f0cd890dbcc3d9e751499086cf6ad6d0e Mon Sep 17 00:00:00 2001 From: Louis Chang Date: Tue, 18 May 2021 15:50:55 +0800 Subject: [PATCH] Only allow system or sysui to set launch activity type Or starting assistance type activity from assistant is also allowed. Otherwise, apps can only start standard activity or other type of activities based on the given intent (such as home activity). Bug: 185872145 Test: atest StartActivityTests Test: atest AssistantStackTests Change-Id: Iba1d19f1ac5e9008580c96a556f3eeab81f112fe --- .../server/wm/ActivityTaskManagerService.java | 23 ++++--- .../server/wm/SafeActivityOptions.java | 62 +++++++++++++++++-- 2 files changed, 71 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 37a9b8012cb75..c7e4abbe3db59 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -1638,15 +1638,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()"); userId = handleIncomingUser(callingPid, callingUid, userId, "startAssistantActivity"); - return getActivityStartController().obtainStarter(intent, "startAssistantActivity") - .setCallingUid(callingUid) - .setCallingPackage(callingPackage) - .setCallingFeatureId(callingFeatureId) - .setResolvedType(resolvedType) - .setActivityOptions(bOptions) - .setUserId(userId) - .setAllowBackgroundActivityStart(true) - .execute(); + final long origId = Binder.clearCallingIdentity(); + try { + return getActivityStartController().obtainStarter(intent, "startAssistantActivity") + .setCallingUid(callingUid) + .setCallingPackage(callingPackage) + .setCallingFeatureId(callingFeatureId) + .setResolvedType(resolvedType) + .setActivityOptions(bOptions) + .setUserId(userId) + .setAllowBackgroundActivityStart(true) + .execute(); + } finally { + Binder.restoreCallingIdentity(origId); + } } /** diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java index c9d5fa473ea89..4892005631ba4 100644 --- a/services/core/java/com/android/server/wm/SafeActivityOptions.java +++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java @@ -20,6 +20,9 @@ import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIO import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.Manifest.permission.STATUS_BAR_SERVICE; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.activityTypeToString; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.view.Display.INVALID_DISPLAY; @@ -29,12 +32,15 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS import android.annotation.Nullable; import android.app.ActivityOptions; +import android.app.AppGlobals; import android.app.PendingIntent; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.Bundle; import android.os.Process; +import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import android.view.RemoteAnimationAdapter; @@ -281,19 +287,65 @@ public class SafeActivityOptions { } // If launched from bubble is specified, then ensure that the caller is system or sysui. - if (options.getLaunchedFromBubble() && callingUid != Process.SYSTEM_UID) { - final int statusBarPerm = ActivityTaskManagerService.checkPermission( - STATUS_BAR_SERVICE, callingPid, callingUid); - if (statusBarPerm == PERMISSION_DENIED) { + if (options.getLaunchedFromBubble() && !isSystemOrSystemUI(callingPid, callingUid)) { + final String msg = "Permission Denial: starting " + getIntentString(intent) + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ") with launchedFromBubble=true"; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + + final int activityType = options.getLaunchActivityType(); + if (activityType != ACTIVITY_TYPE_UNDEFINED + && !isSystemOrSystemUI(callingPid, callingUid)) { + // Granted if it is assistant type and the calling uid is assistant. + boolean activityTypeGranted = false; + if (activityType == ACTIVITY_TYPE_ASSISTANT + && isAssistant(supervisor.mService, callingUid)) { + activityTypeGranted = true; + } + + if (!activityTypeGranted) { final String msg = "Permission Denial: starting " + getIntentString(intent) + " from " + callerApp + " (pid=" + callingPid - + ", uid=" + callingUid + ") with launchedFromBubble=true"; + + ", uid=" + callingUid + ") with launchActivityType=" + + activityTypeToString(options.getLaunchActivityType()); Slog.w(TAG, msg); throw new SecurityException(msg); } } } + private boolean isAssistant(ActivityTaskManagerService atmService, int callingUid) { + if (atmService.mActiveVoiceInteractionServiceComponent == null) { + return false; + } + + final String assistantPackage = + atmService.mActiveVoiceInteractionServiceComponent.getPackageName(); + try { + final int uid = AppGlobals.getPackageManager().getPackageUid(assistantPackage, + PackageManager.MATCH_DIRECT_BOOT_AUTO, + UserHandle.getUserId(callingUid)); + if (uid == callingUid) { + return true; + } + } catch (RemoteException e) { + // Should not happen + } + return false; + } + + private boolean isSystemOrSystemUI(int callingPid, int callingUid) { + if (callingUid == Process.SYSTEM_UID) { + return true; + } + + final int statusBarPerm = ActivityTaskManagerService.checkPermission( + STATUS_BAR_SERVICE, callingPid, callingUid); + return statusBarPerm == PERMISSION_GRANTED; + } + private String getIntentString(Intent intent) { return intent != null ? intent.toString() : "(no intent)"; }