diff options
8 files changed, 372 insertions, 1 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 7dedbd8daf1a..321d35de5249 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -5425,6 +5425,7 @@ package android.app {    @FlaggedApi("android.security.content_uri_permission_apis") public final class ComponentCaller {      ctor public ComponentCaller(@NonNull android.os.IBinder, @Nullable android.os.IBinder); +    method public int checkContentUriPermission(@NonNull android.net.Uri, int);      method @Nullable public String getPackage();      method public int getUid();    } diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java index b8bd030872c1..a59f04bf4f3a 100644 --- a/core/java/android/app/ActivityClient.java +++ b/core/java/android/app/ActivityClient.java @@ -17,13 +17,16 @@  package android.app;  import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; +import static android.os.UserHandle.getCallingUserId;  import android.annotation.Nullable;  import android.annotation.RequiresPermission;  import android.content.ComponentName; +import android.content.ContentProvider;  import android.content.Intent;  import android.content.res.Configuration;  import android.content.res.Resources; +import android.net.Uri;  import android.os.Bundle;  import android.os.IBinder;  import android.os.IRemoteCallback; @@ -296,6 +299,18 @@ public class ActivityClient {          }      } +    /** Checks if the app that launched the activity has access to the URI. */ +    public int checkActivityCallerContentUriPermission(IBinder activityToken, IBinder callerToken, +            Uri uri, int modeFlags) { +        try { +            return getActivityClientController().checkActivityCallerContentUriPermission( +                    activityToken, callerToken, ContentProvider.getUriWithoutUserId(uri), modeFlags, +                    ContentProvider.getUserIdFromUri(uri, getCallingUserId())); +        } catch (RemoteException e) { +            throw e.rethrowFromSystemServer(); +        } +    } +      public void setRequestedOrientation(IBinder token, int requestedOrientation) {          try {              getActivityClientController().setRequestedOrientation(token, requestedOrientation); diff --git a/core/java/android/app/ComponentCaller.java b/core/java/android/app/ComponentCaller.java index 583408ed8db9..a440dbc48db6 100644 --- a/core/java/android/app/ComponentCaller.java +++ b/core/java/android/app/ComponentCaller.java @@ -18,6 +18,9 @@ package android.app;  import android.annotation.FlaggedApi;  import android.annotation.Nullable; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri;  import android.os.IBinder;  import android.os.Process; @@ -118,6 +121,40 @@ public final class ComponentCaller {          return ActivityClient.getInstance().getLaunchedFromPackage(mActivityToken);      } +    /** +     * Determines whether this component caller had access to a specific content URI at launch time. +     * Apps can use this API to validate content URIs coming from other apps. +     * +     * <p><b>Note</b>, in {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} only +     * {@link Activity} has access to {@link ComponentCaller} instances. +     * +     * <p>Before using this method, note the following: +     * <ul> +     *     <li>You must have access to the supplied URI, otherwise it will throw a +     *     {@link SecurityException}. +     *     <li>This is not a real time check, i.e. the permissions have been computed at launch +     *     time. +     *     <li>This method will return the correct result for content URIs passed at launch time, +     *     specifically the ones from {@link Intent#getData()}, and {@link Intent#getClipData()} in +     *     the intent of {@code startActivity(intent)}. For others, it will throw an +     *     {@link IllegalArgumentException}. +     * </ul> +     * +     * @param uri The content uri that is being checked +     * @param modeFlags The access modes to check +     * @return {@link PackageManager#PERMISSION_GRANTED} if this activity caller is allowed to +     *         access that uri, or {@link PackageManager#PERMISSION_DENIED} if it is not +     * @throws IllegalArgumentException if uri is a non-content URI or it wasn't passed at launch +     * @throws SecurityException if you don't have access to uri +     * +     * @see android.content.Context#checkContentUriPermissionFull(Uri, int, int, int) +     */ +    @PackageManager.PermissionResult +    public int checkContentUriPermission(@NonNull Uri uri, @Intent.AccessUriMode int modeFlags) { +        return ActivityClient.getInstance().checkActivityCallerContentUriPermission(mActivityToken, +                mCallerToken, uri, modeFlags); +    } +      @Override      public boolean equals(@Nullable Object obj) {          if (obj == null || !(obj instanceof ComponentCaller other)) { diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl index 5b044f616487..05fee72b7e61 100644 --- a/core/java/android/app/IActivityClientController.aidl +++ b/core/java/android/app/IActivityClientController.aidl @@ -23,6 +23,7 @@ import android.app.PictureInPictureParams;  import android.content.ComponentName;  import android.content.Intent;  import android.content.res.Configuration; +import android.net.Uri;  import android.os.Bundle;  import android.os.IRemoteCallback;  import android.os.PersistableBundle; @@ -91,6 +92,9 @@ interface IActivityClientController {      int getLaunchedFromUid(in IBinder token);      String getLaunchedFromPackage(in IBinder token); +    int checkActivityCallerContentUriPermission(in IBinder activityToken, in IBinder callerToken, +            in Uri uri, int modeFlags, int userId); +      void setRequestedOrientation(in IBinder token, int requestedOrientation);      int getRequestedOrientation(in IBinder token); diff --git a/services/core/java/com/android/server/wm/ActivityCallerState.java b/services/core/java/com/android/server/wm/ActivityCallerState.java new file mode 100644 index 000000000000..4416605d9f04 --- /dev/null +++ b/services/core/java/com/android/server/wm/ActivityCallerState.java @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; + +import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; +import static org.xmlpull.v1.XmlPullParser.END_TAG; +import static org.xmlpull.v1.XmlPullParser.START_TAG; + +import android.content.ClipData; +import android.content.ContentProvider; +import android.content.ContentResolver; +import android.content.Intent; +import android.net.Uri; +import android.os.IBinder; +import android.os.UserHandle; +import android.util.ArraySet; +import android.util.Slog; + +import com.android.internal.util.XmlUtils; +import com.android.modules.utils.TypedXmlPullParser; +import com.android.modules.utils.TypedXmlSerializer; +import com.android.server.uri.GrantUri; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.WeakHashMap; + +/** + * Represents the state of activity callers. Used by {@link ActivityRecord}. + * @hide + */ +final class ActivityCallerState { +    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityCallerState" : TAG_ATM; + +    // XML tags for CallerInfo +    private static final String TAG_READABLE_CONTENT_URI = "readable_content_uri"; +    private static final String TAG_WRITABLE_CONTENT_URI = "writable_content_uri"; +    private static final String TAG_INACCESSIBLE_CONTENT_URI = "inaccessible_content_uri"; +    private static final String ATTR_SOURCE_USER_ID = "source_user_id"; +    private static final String ATTR_URI = "uri"; +    private static final String ATTR_PREFIX = "prefix"; + +    // Map for storing CallerInfo instances +    private final WeakHashMap<IBinder, CallerInfo> mCallerTokenInfoMap = new WeakHashMap<>(); + +    final ActivityTaskManagerService mAtmService; + +    ActivityCallerState(ActivityTaskManagerService service) { +        mAtmService = service; +    } + +    CallerInfo getCallerInfoOrNull(IBinder callerToken) { +        return mCallerTokenInfoMap.getOrDefault(callerToken, null); +    } + +    void add(IBinder callerToken, CallerInfo callerInfo) { +        mCallerTokenInfoMap.put(callerToken, callerInfo); +    } + +    void computeCallerInfo(IBinder callerToken, Intent intent, int callerUid) { +        final CallerInfo callerInfo = new CallerInfo(); +        mCallerTokenInfoMap.put(callerToken, callerInfo); + +        final ArraySet<Uri> contentUris = getContentUrisFromIntent(intent); +        for (int i = contentUris.size() - 1; i >= 0; i--) { +            final Uri contentUri = contentUris.valueAt(i); + +            final boolean hasRead = addContentUriIfUidHasPermission(contentUri, callerUid, +                    Intent.FLAG_GRANT_READ_URI_PERMISSION, callerInfo.mReadableContentUris); + +            final boolean hasWrite = addContentUriIfUidHasPermission(contentUri, callerUid, +                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION, callerInfo.mWritableContentUris); + +            if (!hasRead && !hasWrite) { +                callerInfo.mInaccessibleContentUris.add(convertToGrantUri(contentUri, +                        /* modeFlags */ 0)); +            } +        } +    } + +    boolean checkContentUriPermission(IBinder callerToken, GrantUri grantUri, int modeFlags) { +        if (!Intent.isAccessUriMode(modeFlags)) { +            throw new IllegalArgumentException("Mode flags are not access URI mode flags: " +                    + modeFlags); +        } + +        final CallerInfo callerInfo = mCallerTokenInfoMap.getOrDefault(callerToken, null); +        if (callerInfo == null) { +            Slog.e(TAG, "Caller not found for checkContentUriPermission of: " +                    + grantUri.uri.toSafeString()); +            return false; +        } + +        if (callerInfo.mInaccessibleContentUris.contains(grantUri)) { +            return false; +        } + +        final boolean readMet = callerInfo.mReadableContentUris.contains(grantUri); +        final boolean writeMet = callerInfo.mWritableContentUris.contains(grantUri); + +        if (!readMet && !writeMet) { +            throw new IllegalArgumentException("The supplied URI wasn't passed at launch: " +                    + grantUri.uri.toSafeString()); +        } + +        final boolean checkRead = (modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0; +        if (checkRead && !readMet) { +            return false; +        } + +        final boolean checkWrite = (modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0; +        if (checkWrite && !writeMet) { +            return false; +        } + +        return true; +    } + +    private boolean addContentUriIfUidHasPermission(Uri contentUri, int uid, int modeFlags, +            ArraySet<GrantUri> grantUris) { +        final GrantUri grantUri = convertToGrantUri(contentUri, modeFlags); +        if (mAtmService.mUgmInternal.checkUriPermission(grantUri, uid, +                modeFlags, /* isFullAccessForContentUri */ true)) { +            grantUris.add(grantUri); +            return true; +        } +        return false; +    } + +    private static GrantUri convertToGrantUri(Uri contentUri, int modeFlags) { +        return new GrantUri(ContentProvider.getUserIdFromUri(contentUri, +                UserHandle.getCallingUserId()), ContentProvider.getUriWithoutUserId(contentUri), +                modeFlags); +    } + +    private static ArraySet<Uri> getContentUrisFromIntent(Intent intent) { +        final ArraySet<Uri> uris = new ArraySet<>(); +        if (intent == null) return uris; + +        // getData +        addUriIfContentUri(intent.getData(), uris); + +        final ClipData clipData = intent.getClipData(); +        if (clipData == null) return uris; + +        for (int i = 0; i < clipData.getItemCount(); i++) { +            final ClipData.Item item = clipData.getItemAt(i); + +            // getUri +            addUriIfContentUri(item.getUri(), uris); + +            // getIntent +            uris.addAll(getContentUrisFromIntent(item.getIntent())); +        } +        return uris; +    } + +    private static void addUriIfContentUri(Uri uri, ArraySet<Uri> uris) { +        if (uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { +            uris.add(uri); +        } +    } + +    public static final class CallerInfo { +        final ArraySet<GrantUri> mReadableContentUris = new ArraySet<>(); +        final ArraySet<GrantUri> mWritableContentUris = new ArraySet<>(); +        final ArraySet<GrantUri> mInaccessibleContentUris = new ArraySet<>(); + +        public void saveToXml(TypedXmlSerializer out) +                throws IOException, XmlPullParserException { +            for (int i = mReadableContentUris.size() - 1; i >= 0; i--) { +                saveGrantUriToXml(out, mReadableContentUris.valueAt(i), TAG_READABLE_CONTENT_URI); +            } + +            for (int i = mWritableContentUris.size() - 1; i >= 0; i--) { +                saveGrantUriToXml(out, mWritableContentUris.valueAt(i), TAG_WRITABLE_CONTENT_URI); +            } + +            for (int i = mInaccessibleContentUris.size() - 1; i >= 0; i--) { +                saveGrantUriToXml(out, mInaccessibleContentUris.valueAt(i), +                        TAG_INACCESSIBLE_CONTENT_URI); +            } +        } + +        public static CallerInfo restoreFromXml(TypedXmlPullParser in) +                throws IOException, XmlPullParserException { +            CallerInfo callerInfo = new CallerInfo(); +            final int outerDepth = in.getDepth(); +            int event; +            while (((event = in.next()) != END_DOCUMENT) +                    && (event != END_TAG || in.getDepth() >= outerDepth)) { +                if (event == START_TAG) { +                    final String name = in.getName(); +                    if (TAG_READABLE_CONTENT_URI.equals(name)) { +                        callerInfo.mReadableContentUris.add(restoreGrantUriFromXml(in)); +                    } else if (TAG_WRITABLE_CONTENT_URI.equals(name)) { +                        callerInfo.mWritableContentUris.add(restoreGrantUriFromXml(in)); +                    } else if (TAG_INACCESSIBLE_CONTENT_URI.equals(name)) { +                        callerInfo.mInaccessibleContentUris.add(restoreGrantUriFromXml(in)); +                    } else { +                        Slog.w(TAG, "restoreActivity: unexpected name=" + name); +                        XmlUtils.skipCurrentTag(in); +                    } +                } +            } +            return callerInfo; +        } + +        private void saveGrantUriToXml(TypedXmlSerializer out, GrantUri grantUri, String tag) +                throws IOException, XmlPullParserException { +            out.startTag(null, tag); +            out.attributeInt(null, ATTR_SOURCE_USER_ID, grantUri.sourceUserId); +            out.attribute(null, ATTR_URI, String.valueOf(grantUri.uri)); +            out.attributeBoolean(null, ATTR_PREFIX, grantUri.prefix); +            out.endTag(null, tag); +        } + +        private static GrantUri restoreGrantUriFromXml(TypedXmlPullParser in) +                throws IOException, XmlPullParserException { +            int sourceUserId = in.getAttributeInt(null, ATTR_SOURCE_USER_ID, 0); +            Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI)); +            boolean prefix = in.getAttributeBoolean(null, ATTR_PREFIX, false); +            return new GrantUri(sourceUserId, uri, +                    prefix ? Intent.FLAG_GRANT_PREFIX_URI_PERMISSION : 0); +        } +    } +} diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index 2e0546eee8e7..173e139e124c 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -30,6 +30,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;  import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;  import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;  import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.content.pm.PackageManager.PERMISSION_DENIED; +import static android.content.pm.PackageManager.PERMISSION_GRANTED;  import static android.os.Process.INVALID_UID;  import static android.os.Process.SYSTEM_UID;  import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; @@ -80,6 +82,7 @@ import android.content.Intent;  import android.content.pm.ActivityInfo;  import android.content.pm.PackageManagerInternal;  import android.content.res.Configuration; +import android.net.Uri;  import android.os.Binder;  import android.os.Bundle;  import android.os.IBinder; @@ -103,6 +106,7 @@ import com.android.server.LocalServices;  import com.android.server.Watchdog;  import com.android.server.pm.KnownPackages;  import com.android.server.pm.pkg.AndroidPackage; +import com.android.server.uri.GrantUri;  import com.android.server.uri.NeededUriGrants;  import com.android.server.vr.VrManagerInternal; @@ -715,6 +719,32 @@ class ActivityClientController extends IActivityClientController.Stub {          return null;      } +    /** +     * @param uri This uri must NOT contain an embedded userId. +     * @param userId The userId in which the uri is to be resolved. +     */ +    @Override +    public int checkActivityCallerContentUriPermission(IBinder activityToken, IBinder callerToken, +            Uri uri, int modeFlags, int userId) { +        // 1. Check if we have access to the URI - > throw if we don't +        GrantUri grantUri = new GrantUri(userId, uri, modeFlags); +        if (!mService.mUgmInternal.checkUriPermission(grantUri, Binder.getCallingUid(), modeFlags, +                /* isFullAccessForContentUri */ true)) { +            throw new SecurityException("You don't have access to the content URI, hence can't" +                    + " check if the caller has access to it: " + uri); +        } + +        // 2. Get the permission result for the caller +        synchronized (mGlobalLock) { +            final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken); +            if (r != null) { +                boolean granted = r.checkContentUriPermission(callerToken, grantUri, modeFlags); +                return granted ? PERMISSION_GRANTED : PERMISSION_DENIED; +            } +        } +        return PERMISSION_DENIED; +    } +      /** 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) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index c2117eaa72c4..09c329be7d09 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -381,6 +381,7 @@ import com.android.server.am.PendingIntentRecord;  import com.android.server.contentcapture.ContentCaptureManagerInternal;  import com.android.server.display.color.ColorDisplayService;  import com.android.server.pm.UserManagerInternal; +import com.android.server.uri.GrantUri;  import com.android.server.uri.NeededUriGrants;  import com.android.server.uri.UriPermissionOwner;  import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot; @@ -436,6 +437,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A      private static final String ATTR_LAUNCHEDFROMFEATURE = "launched_from_feature";      private static final String ATTR_RESOLVEDTYPE = "resolved_type";      private static final String ATTR_COMPONENTSPECIFIED = "component_specified"; +    private static final String TAG_INITIAL_CALLER_INFO = "initial_caller_info";      static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";      // How many activities have to be scheduled to stop to force a stop pass. @@ -472,6 +474,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A      private static final float ASPECT_RATIO_ROUNDING_TOLERANCE = 0.005f;      final ActivityTaskManagerService mAtmService; +    final ActivityCallerState mCallerState;      @NonNull      final ActivityInfo info; // activity info provided by developer in AndroidManifest      // Which user is this running for? @@ -2021,6 +2024,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A          }      } +    void computeInitialCallerInfo() { +        computeCallerInfo(initialCallerInfoAccessToken, intent, launchedFromUid); +    } + +    void computeCallerInfo(IBinder callerToken, Intent intent, int callerUid) { +        mCallerState.computeCallerInfo(callerToken, intent, callerUid); +    } + +    boolean checkContentUriPermission(IBinder callerToken, GrantUri grantUri, int modeFlags) { +        return mCallerState.checkContentUriPermission(callerToken, grantUri, modeFlags); +    } +      private ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,              int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage,              @Nullable String _launchedFromFeature, Intent _intent, String _resolvedType, @@ -2246,6 +2261,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A                              }                              return appContext;                          }); +        mCallerState = new ActivityCallerState(mAtmService);      }      /** @@ -10113,6 +10129,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A              mPersistentState.saveToXml(out);              out.endTag(null, TAG_PERSISTABLEBUNDLE);          } + +        if (android.security.Flags.contentUriPermissionApis()) { +            ActivityCallerState.CallerInfo initialCallerInfo = mCallerState.getCallerInfoOrNull( +                    initialCallerInfoAccessToken); +            if (initialCallerInfo != null) { +                out.startTag(null, TAG_INITIAL_CALLER_INFO); +                initialCallerInfo.saveToXml(out); +                out.endTag(null, TAG_INITIAL_CALLER_INFO); +            } +        }      }      static ActivityRecord restoreFromXml(TypedXmlPullParser in, @@ -10127,6 +10153,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A          int userId = in.getAttributeInt(null, ATTR_USERID, 0);          long createTime = in.getAttributeLong(null, ATTR_ID, -1);          final int outerDepth = in.getDepth(); +        ActivityCallerState.CallerInfo initialCallerInfo = null;          TaskDescription taskDescription = new TaskDescription();          taskDescription.restoreFromXml(in); @@ -10146,6 +10173,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A                      persistentState = PersistableBundle.restoreFromXml(in);                      if (DEBUG) Slog.d(TaskPersister.TAG,                              "ActivityRecord: persistentState=" + persistentState); +                } else if (android.security.Flags.contentUriPermissionApis() +                        && TAG_INITIAL_CALLER_INFO.equals(name)) { +                    initialCallerInfo = ActivityCallerState.CallerInfo.restoreFromXml(in);                  } else {                      Slog.w(TAG, "restoreActivity: unexpected name=" + name);                      XmlUtils.skipCurrentTag(in); @@ -10164,7 +10194,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A              throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent +                      " resolvedType=" + resolvedType);          } -        return new ActivityRecord.Builder(service) +        final ActivityRecord r = new ActivityRecord.Builder(service)                  .setLaunchedFromUid(launchedFromUid)                  .setLaunchedFromPackage(launchedFromPackage)                  .setLaunchedFromFeature(launchedFromFeature) @@ -10176,6 +10206,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A                  .setTaskDescription(taskDescription)                  .setCreateTime(createTime)                  .build(); + +        if (android.security.Flags.contentUriPermissionApis() && initialCallerInfo != null) { +            r.mCallerState.add(r.initialCallerInfoAccessToken, initialCallerInfo); +        } +        return r;      }      private static boolean isInVrUiMode(Configuration config) { diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index d99000efeeb4..07afa5fc21be 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1586,6 +1586,10 @@ class ActivityStarter {              return null;          } +        if (android.security.Flags.contentUriPermissionApis() && started.isAttached()) { +            started.computeInitialCallerInfo(); +        } +          // Apply setAlwaysOnTop when starting an activity is successful regardless of creating          // a new Activity or reusing the existing activity.          if (options != null && options.getTaskAlwaysOnTop()) {  |