Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 572ed7fc authored by Martijn Coenen's avatar Martijn Coenen
Browse files

Fix Application Zygote use for external services.

External services are services that are hosted in a particular
application, but run under the packageName and uid of the calling
application (in order to be able to blame the service correctly). When
using an external service in combination with the AppZygote, the
AppZygote needs to run under the uid and packageName of the application
hosting the actual service, not the caller.

Use the newly introduced HostingRecord class to store information about
the application that is actually hosting the service, so we can create
the AppZygote correctly.

Bug: 127820394
Test: atest CtsExternalServiceTestCases (modified to include app zygote)
      atest android.app.cts.ServiceTest
      atest CtsSeccompHostTestCases
Change-Id: Iac75e4f7a49622a9df70a272bae311da1988e3e9
parent e8431c29
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -2117,6 +2117,12 @@ public final class ActiveServices {
                    Slog.w(TAG, "Service lookup failed: " + msg);
                    return new ServiceLookupResult(null, msg);
                }

                // Store the defining packageName and uid, as they might be changed in
                // the ApplicationInfo for external services (which run with the package name
                // and uid of the caller).
                String definingPackageName = sInfo.applicationInfo.packageName;
                int definingUid = sInfo.applicationInfo.uid;
                if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {
                    if (isBindExternal) {
                        if (!sInfo.exported) {
@@ -2175,8 +2181,8 @@ public final class ActiveServices {
                                sInfo.applicationInfo.uid, name.getPackageName(),
                                name.getClassName());
                    }
                    r = new ServiceRecord(mAm, ss, className, name, filter, sInfo,
                            callingFromFg, res);
                    r = new ServiceRecord(mAm, ss, className, name, definingPackageName,
                            definingUid, filter, sInfo, callingFromFg, res);
                    res.setService(r);
                    smap.mServicesByInstanceName.put(name, r);
                    smap.mServicesByIntent.put(filter, r);
@@ -2591,7 +2597,8 @@ public final class ActiveServices {
                hostingRecord = HostingRecord.byWebviewZygote(r.instanceName);
            }
            if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
                hostingRecord = HostingRecord.byAppZygote(r.instanceName);
                hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName,
                        r.definingUid);
            }
        }

+4 −2
Original line number Diff line number Diff line
@@ -1964,7 +1964,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                ProcessRecord app = mProcessList.newProcessRecordLocked(info, info.processName,
                        false,
                        0,
                        false);
                        new HostingRecord("system"));
                app.setPersistent(true);
                app.pid = MY_PID;
                app.getWindowProcessController().setPid(MY_PID);
@@ -7641,7 +7641,9 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
        if (app == null) {
            app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0, false);
            app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0,
                    new HostingRecord("added application",
                            customProcess != null ? customProcess : info.processName));
            mProcessList.updateLruProcessLocked(app, false, null);
            updateOomAdjLocked();
        }
+56 −7
Original line number Diff line number Diff line
@@ -21,13 +21,25 @@ import android.content.ComponentName;
/**
 * This class describes various information required to start a process.
 *
 * The {@link #mHostingType} parameter describes the reason why we started a process, and
 * The {@code mHostingType} field describes the reason why we started a process, and
 * is only used for logging and stats.
 *
 * The {@link #mHostingName} parameter describes the Component for which we are starting the
 * The {@code mHostingName} field describes the Component for which we are starting the
 * process, and is only used for logging and stats.
 *
 * The {@link #mHostingZygote} describes from which Zygote the new process should be spawned.
 * The {@code mHostingZygote} field describes from which Zygote the new process should be spawned.
 *
 * {@code mDefiningPackageName} contains the packageName of the package that defines the
 * component we want to start; this can be different from the packageName and uid in the
 * ApplicationInfo that we're creating the process with, in case the service is a
 * {@link android.content.Context#BIND_EXTERNAL_SERVICE} service. In that case, the packageName
 * and uid in the ApplicationInfo will be set to those of the caller, not of the defining package.
 *
 * {@code mDefiningUid} contains the uid of the application that defines the component we want to
 * start; this can be different from the packageName and uid in the ApplicationInfo that we're
 * creating the process with, in case the service is a
 * {@link android.content.Context#BIND_EXTERNAL_SERVICE} service. In that case, the packageName
 * and uid in the ApplicationInfo will be set to those of the caller, not of the defining package.
 *
 */

@@ -39,23 +51,36 @@ public final class HostingRecord {
    private final String mHostingType;
    private final String mHostingName;
    private final int mHostingZygote;
    private final String mDefiningPackageName;
    private final int mDefiningUid;

    public HostingRecord(String hostingType) {
        this(hostingType, null, REGULAR_ZYGOTE);
        this(hostingType, null, REGULAR_ZYGOTE, null, -1);
    }

    public HostingRecord(String hostingType, ComponentName hostingName) {
        this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE);
        this(hostingType, hostingName, REGULAR_ZYGOTE);
    }

    public HostingRecord(String hostingType, String hostingName) {
        this(hostingType, hostingName, REGULAR_ZYGOTE);
    }

    private HostingRecord(String hostingType, ComponentName hostingName, int hostingZygote) {
        this(hostingType, hostingName.toShortString(), hostingZygote);
    }

    private HostingRecord(String hostingType, String hostingName, int hostingZygote) {
        this(hostingType, hostingName, hostingZygote, null, -1);
    }

    private HostingRecord(String hostingType, String hostingName, int hostingZygote,
            String definingPackageName, int definingUid) {
        mHostingType = hostingType;
        mHostingName = hostingName;
        mHostingZygote = hostingZygote;
        mDefiningPackageName = definingPackageName;
        mDefiningUid = definingUid;
    }

    public String getType() {
@@ -66,6 +91,26 @@ public final class HostingRecord {
        return mHostingName;
    }

    /**
     * Returns the UID of the package defining the component we want to start. Only valid
     * when {@link #usesAppZygote()} returns true.
     *
     * @return the UID of the hosting application
     */
    public int getDefiningUid() {
        return mDefiningUid;
    }

    /**
     * Returns the packageName of the package defining the component we want to start. Only valid
     * when {@link #usesAppZygote()} returns true.
     *
     * @return the packageName of the hosting application
     */
    public String getDefiningPackageName() {
        return mDefiningPackageName;
    }

    /**
     * Creates a HostingRecord for a process that must spawn from the webview zygote
     * @param hostingName name of the component to be hosted in this process
@@ -78,10 +123,14 @@ public final class HostingRecord {
    /**
     * Creates a HostingRecord for a process that must spawn from the application zygote
     * @param hostingName name of the component to be hosted in this process
     * @param definingPackageName name of the package defining the service
     * @param definingUid uid of the package defining the service
     * @return The constructed HostingRecord
     */
    public static HostingRecord byAppZygote(ComponentName hostingName) {
        return new HostingRecord("", hostingName.toShortString(), APP_ZYGOTE);
    public static HostingRecord byAppZygote(ComponentName hostingName, String definingPackageName,
            int definingUid) {
        return new HostingRecord("", hostingName.toShortString(), APP_ZYGOTE,
                definingPackageName, definingUid);
    }

    /**
+40 −19
Original line number Diff line number Diff line
@@ -454,13 +454,13 @@ public final class ProcessList {
        }

        @GuardedBy("ProcessList.this.mService")
        IsolatedUidRange getIsolatedUidRangeLocked(ApplicationInfo info) {
            return mAppRanges.get(info.processName, info.uid);
        IsolatedUidRange getIsolatedUidRangeLocked(String processName, int uid) {
            return mAppRanges.get(processName, uid);
        }

        @GuardedBy("ProcessList.this.mService")
        IsolatedUidRange getOrCreateIsolatedUidRangeLocked(ApplicationInfo info) {
            IsolatedUidRange range = getIsolatedUidRangeLocked(info);
        IsolatedUidRange getOrCreateIsolatedUidRangeLocked(String processName, int uid) {
            IsolatedUidRange range = getIsolatedUidRangeLocked(processName, uid);
            if (range == null) {
                int uidRangeIndex = mAvailableUidRanges.nextSetBit(0);
                if (uidRangeIndex < 0) {
@@ -470,7 +470,7 @@ public final class ProcessList {
                mAvailableUidRanges.clear(uidRangeIndex);
                int actualUid = mFirstUid + uidRangeIndex * mNumUidsPerRange;
                range = new IsolatedUidRange(actualUid, actualUid + mNumUidsPerRange - 1);
                mAppRanges.put(info.processName, info.uid, range);
                mAppRanges.put(processName, uid, range);
            }
            return range;
        }
@@ -1726,12 +1726,14 @@ public final class ProcessList {
    private void removeProcessFromAppZygoteLocked(final ProcessRecord app) {
        // Free the isolated uid for this process
        final IsolatedUidRange appUidRange =
                mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info);
                mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info.processName,
                        app.hostingRecord.getDefiningUid());
        if (appUidRange != null) {
            appUidRange.freeIsolatedUidLocked(app.uid);
        }

        final AppZygote appZygote = mAppZygotes.get(app.info.processName, app.info.uid);
        final AppZygote appZygote = mAppZygotes.get(app.info.processName,
                app.hostingRecord.getDefiningUid());
        if (appZygote != null) {
            ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote);
            zygoteProcesses.remove(app);
@@ -1752,21 +1754,40 @@ public final class ProcessList {

    private AppZygote createAppZygoteForProcessIfNeeded(final ProcessRecord app) {
        synchronized (mService) {
            AppZygote appZygote = mAppZygotes.get(app.info.processName, app.info.uid);
            // The UID for the app zygote should be the UID of the application hosting
            // the service.
            final int uid = app.hostingRecord.getDefiningUid();
            AppZygote appZygote = mAppZygotes.get(app.info.processName, uid);
            final ArrayList<ProcessRecord> zygoteProcessList;
            if (appZygote == null) {
                if (DEBUG_PROCESSES) {
                    Slog.d(TAG_PROCESSES, "Creating new app zygote.");
                }
                final IsolatedUidRange uidRange =
                        mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info);
                final int userId = UserHandle.getUserId(app.info.uid);
                        mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(
                                app.info.processName, app.hostingRecord.getDefiningUid());
                final int userId = UserHandle.getUserId(uid);
                // Create the app-zygote and provide it with the UID-range it's allowed
                // to setresuid/setresgid to.
                final int firstUid = UserHandle.getUid(userId, uidRange.mFirstUid);
                final int lastUid = UserHandle.getUid(userId, uidRange.mLastUid);
                appZygote = new AppZygote(app.info, app.info.uid, firstUid, lastUid);
                mAppZygotes.put(app.info.processName, app.info.uid, appZygote);
                ApplicationInfo appInfo = new ApplicationInfo(app.info);
                // If this was an external service, the package name and uid in the passed in
                // ApplicationInfo have been changed to match those of the calling package;
                // that is not what we want for the AppZygote though, which needs to have the
                // packageName and uid of the defining application. This is because the
                // preloading only makes sense in the context of the defining application,
                // not the calling one.
                appInfo.packageName = app.hostingRecord.getDefiningPackageName();
                appInfo.uid = uid;
                appZygote = new AppZygote(appInfo, uid, firstUid, lastUid);
                mAppZygotes.put(app.info.processName, uid, appZygote);
                zygoteProcessList = new ArrayList<ProcessRecord>();
                mAppZygoteProcesses.put(appZygote, zygoteProcessList);
            } else {
                if (DEBUG_PROCESSES) {
                    Slog.d(TAG_PROCESSES, "Reusing existing app zygote.");
                }
                mService.mHandler.removeMessages(KILL_APP_ZYGOTE_MSG, appZygote);
                zygoteProcessList = mAppZygoteProcesses.get(appZygote);
            }
@@ -1915,9 +1936,8 @@ public final class ProcessList {
        }

        if (app == null) {
            final boolean fromAppZygote = hostingRecord.usesAppZygote();
            checkSlow(startTime, "startProcess: creating new process record");
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid, fromAppZygote);
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid, hostingRecord);
            if (app == null) {
                Slog.w(TAG, "Failed making new process record for "
                        + processName + "/" + info.uid + " isolated=" + isolated);
@@ -2301,24 +2321,25 @@ public final class ProcessList {

    @GuardedBy("mService")
    private IsolatedUidRange getOrCreateIsolatedUidRangeLocked(ApplicationInfo info,
            boolean fromAppZygote) {
        if (!fromAppZygote) {
            HostingRecord hostingRecord) {
        if (hostingRecord == null || !hostingRecord.usesAppZygote()) {
            // Allocate an isolated UID from the global range
            return mGlobalIsolatedUids;
        } else {
            return mAppIsolatedUidRangeAllocator.getOrCreateIsolatedUidRangeLocked(info);
            return mAppIsolatedUidRangeAllocator.getOrCreateIsolatedUidRangeLocked(
                    info.processName, hostingRecord.getDefiningUid());
        }
    }

    @GuardedBy("mService")
    final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
            boolean isolated, int isolatedUid, boolean fromAppZygote) {
            boolean isolated, int isolatedUid, HostingRecord hostingRecord) {
        String proc = customProcess != null ? customProcess : info.processName;
        final int userId = UserHandle.getUserId(info.uid);
        int uid = info.uid;
        if (isolated) {
            if (isolatedUid == 0) {
                IsolatedUidRange uidRange = getOrCreateIsolatedUidRangeLocked(info, fromAppZygote);
                IsolatedUidRange uidRange = getOrCreateIsolatedUidRangeLocked(info, hostingRecord);
                if (uidRange == null) {
                    return null;
                }
+7 −1
Original line number Diff line number Diff line
@@ -73,6 +73,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
    final ComponentName name; // service component.
    final ComponentName instanceName; // service component's per-instance name.
    final String shortInstanceName; // instanceName.flattenToShortString().
    final String definingPackageName;
                            // Can be different from appInfo.packageName for external services
    final int definingUid;
                            // Can be different from appInfo.uid for external services
    final Intent.FilterComparison intent;
                            // original intent used to find service.
    final ServiceInfo serviceInfo;
@@ -474,7 +478,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN

    ServiceRecord(ActivityManagerService ams,
            BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name,
            ComponentName instanceName,
            ComponentName instanceName, String definingPackageName, int definingUid,
            Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
            Runnable restarter) {
        this.ams = ams;
@@ -482,6 +486,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
        this.name = name;
        this.instanceName = instanceName;
        shortInstanceName = instanceName.flattenToShortString();
        this.definingPackageName = definingPackageName;
        this.definingUid = definingUid;
        this.intent = intent;
        serviceInfo = sInfo;
        appInfo = sInfo.applicationInfo;
Loading