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

Commit aeaea8bd authored by Jing Ji's avatar Jing Ji Committed by Automerger Merge Worker
Browse files

Merge "Provide a system_server internal API to get isolated PIDs of an UID"...

Merge "Provide a system_server internal API to get isolated PIDs of an UID" into sc-dev am: 53459e96

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15102276

Change-Id: I42619e3653343d40a174ada9e30e0c2acc45436a
parents ae13e5ca 53459e96
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -640,4 +640,10 @@ public abstract class ActivityManagerInternal {
     * Returns the capability of the given uid
     */
    public abstract @ProcessCapability int getUidCapability(int uid);

    /**
     * @return The PID list of the isolated process with packages matching the given uid.
     */
    @Nullable
    public abstract List<Integer> getIsolatedProcesses(int uid);
}
+10 −0
Original line number Diff line number Diff line
@@ -16329,6 +16329,16 @@ public class ActivityManagerService extends IActivityManager.Stub
                return uidRecord.getCurCapability();
            }
        }
        /**
         * @return The PID list of the isolated process with packages matching the given uid.
         */
        @Nullable
        public List<Integer> getIsolatedProcesses(int uid) {
            synchronized (ActivityManagerService.this) {
                return mProcessList.getIsolatedProcessesLocked(uid);
            }
        }
    }
    long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
+22 −0
Original line number Diff line number Diff line
@@ -321,6 +321,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
                    return runMemoryFactor(pw);
                case "service-restart-backoff":
                    return runServiceRestartBackoff(pw);
                case "get-isolated-pids":
                    return runGetIsolatedProcesses(pw);
                default:
                    return handleDefaultCommands(cmd);
            }
@@ -3137,6 +3139,24 @@ final class ActivityManagerShellCommand extends ShellCommand {
        }
    }

    private int runGetIsolatedProcesses(PrintWriter pw) throws RemoteException {
        mInternal.enforceCallingPermission(android.Manifest.permission.DUMP,
                "getIsolatedProcesses()");
        final List<Integer> result = mInternal.mInternal.getIsolatedProcesses(
                Integer.parseInt(getNextArgRequired()));
        pw.print("[");
        if (result != null) {
            for (int i = 0, size = result.size(); i < size; i++) {
                if (i > 0) {
                    pw.print(", ");
                }
                pw.print(result.get(i));
            }
        }
        pw.println("]");
        return 0;
    }

    private Resources getResources(PrintWriter pw) throws RemoteException {
        // system resources does not contain all the device configuration, construct it manually.
        Configuration config = mInterface.getConfiguration();
@@ -3467,6 +3487,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
            pw.println("            Toggles the restart backoff policy on/off for <PACKAGE_NAME>.");
            pw.println("         show <PACKAGE_NAME>");
            pw.println("            Shows the restart backoff policy state for <PACKAGE_NAME>.");
            pw.println("  get-isolated-pids <UID>");
            pw.println("         Get the PIDs of isolated processes with packages in this <UID>");
            pw.println();
            Intent.printIntentArgsHelp(pw, "");
        }
+17 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;

import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager.ProcessCapability;
import android.app.ActivityThread;
@@ -2988,6 +2989,22 @@ public final class ProcessList {
        }
    }

    @Nullable
    @GuardedBy("mService")
    List<Integer> getIsolatedProcessesLocked(int uid) {
        List<Integer> ret = null;
        for (int i = 0, size = mIsolatedProcesses.size(); i < size; i++) {
            final ProcessRecord app = mIsolatedProcesses.valueAt(i);
            if (app.info.uid == uid) {
                if (ret == null) {
                    ret = new ArrayList<>();
                }
                ret.add(app.getPid());
            }
        }
        return ret;
    }

    @GuardedBy("mService")
    ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
            boolean isolated, int isolatedUid, HostingRecord hostingRecord) {
+130 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.DropBoxManager;
import android.os.Handler;
@@ -43,7 +44,9 @@ import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
@@ -53,6 +56,7 @@ import android.support.test.uiautomator.UiDevice;
import android.test.suitebuilder.annotation.LargeTest;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.FlakyTest;
@@ -62,11 +66,13 @@ import org.junit.Ignore;
import org.junit.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * Tests for {@link ActivityManager}.
@@ -105,6 +111,9 @@ public class ActivityManagerTest {
    private static final int COMMAND_UNBIND_SERVICE = 3;
    private static final int COMMAND_STOP_SELF = 4;

    private static final String TEST_ISOLATED_CLASS =
            "com.android.servicestests.apps.simpleservicetestapp.SimpleIsolatedService";

    private IActivityManager mService;
    private IRemoteCallback mCallback;
    private Context mContext;
@@ -568,6 +577,127 @@ public class ActivityManagerTest {
        return -1;
    }

    @Test
    public void testGetIsolatedProcesses() throws Exception {
        final ActivityManager am = mContext.getSystemService(ActivityManager.class);
        final PackageManager pm = mContext.getPackageManager();
        final int uid1 = pm.getPackageUid(TEST_APP1, 0);
        final int uid2 = pm.getPackageUid(TEST_APP2, 0);
        final int uid3 = pm.getPackageUid(TEST_APP3, 0);
        final List<Pair<Integer, ServiceConnection>> uid1Processes = new ArrayList<>();
        final List<Pair<Integer, ServiceConnection>> uid2Processes = new ArrayList<>();
        try {
            assertTrue("There shouldn't be any isolated process for " + TEST_APP1,
                    getIsolatedProcesses(uid1).isEmpty());
            assertTrue("There shouldn't be any isolated process for " + TEST_APP2,
                    getIsolatedProcesses(uid2).isEmpty());
            assertTrue("There shouldn't be any isolated process for " + TEST_APP3,
                    getIsolatedProcesses(uid3).isEmpty());

            // Verify uid1
            uid1Processes.add(createIsolatedProcessAndVerify(TEST_APP1, uid1));
            uid1Processes.add(createIsolatedProcessAndVerify(TEST_APP1, uid1));
            uid1Processes.add(createIsolatedProcessAndVerify(TEST_APP1, uid1));
            verifyIsolatedProcesses(uid1Processes, getIsolatedProcesses(uid1));

            // Let one of the processes go
            final Pair<Integer, ServiceConnection> uid1P2 = uid1Processes.remove(2);
            mContext.unbindService(uid1P2.second);
            Thread.sleep(5_000); // Wait for the process gone.
            verifyIsolatedProcesses(uid1Processes, getIsolatedProcesses(uid1));

            // Verify uid2
            uid2Processes.add(createIsolatedProcessAndVerify(TEST_APP2, uid2));
            verifyIsolatedProcesses(uid2Processes, getIsolatedProcesses(uid2));

            // Verify uid1 again
            verifyIsolatedProcesses(uid1Processes, getIsolatedProcesses(uid1));

            // Verify uid3
            assertTrue("There shouldn't be any isolated process for " + TEST_APP3,
                    getIsolatedProcesses(uid3).isEmpty());
        } finally {
            for (Pair<Integer, ServiceConnection> p: uid1Processes) {
                mContext.unbindService(p.second);
            }
            for (Pair<Integer, ServiceConnection> p: uid2Processes) {
                mContext.unbindService(p.second);
            }
            am.forceStopPackage(TEST_APP1);
            am.forceStopPackage(TEST_APP2);
            am.forceStopPackage(TEST_APP3);
        }
    }

    private static List<Integer> getIsolatedProcesses(int uid) throws Exception {
        final String output = runShellCommand("am get-isolated-pids " + uid);
        final Matcher matcher = Pattern.compile("(\\d+)").matcher(output);
        final List<Integer> pids = new ArrayList<>();
        while (matcher.find()) {
            pids.add(Integer.parseInt(output.substring(matcher.start(), matcher.end())));
        }
        return pids;
    }

    private void verifyIsolatedProcesses(List<Pair<Integer, ServiceConnection>> processes,
            List<Integer> pids) {
        final List<Integer> l = processes.stream().map(p -> p.first).collect(Collectors.toList());
        assertTrue("Isolated processes don't match", l.containsAll(pids));
        assertTrue("Isolated processes don't match", pids.containsAll(l));
    }

    private Pair<Integer, ServiceConnection> createIsolatedProcessAndVerify(String pkgName, int uid)
            throws Exception {
        final Pair<Integer, ServiceConnection> p = createIsolatedProcess(pkgName);
        final List<Integer> pids = getIsolatedProcesses(uid);
        assertTrue("Can't find the isolated pid " + p.first + " for " + pkgName,
                pids.contains(p.first));
        return p;
    }

    private Pair<Integer, ServiceConnection> createIsolatedProcess(String pkgName)
            throws Exception {
        final int[] pid = new int[1];
        final CountDownLatch[] latch = new CountDownLatch[1];
        final ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                final IRemoteCallback s = IRemoteCallback.Stub.asInterface(service);
                final IBinder callback = new Binder() {
                    @Override
                    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
                            throws RemoteException {
                        if (code == Binder.FIRST_CALL_TRANSACTION) {
                            pid[0] = data.readInt();
                            latch[0].countDown();
                            return true;
                        }
                        return super.onTransact(code, data, reply, flags);
                    }
                };
                try {
                    final Bundle extra = new Bundle();
                    extra.putBinder(EXTRA_CALLBACK, callback);
                    s.sendResult(extra);
                } catch (RemoteException e) {
                    fail("Unable to call into isolated process");
                }
            }
            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        };
        final Intent intent = new Intent();
        intent.setClassName(pkgName, TEST_ISOLATED_CLASS);
        latch[0] = new CountDownLatch(1);
        assertTrue("Unable to create isolated process in " + pkgName,
                mContext.bindIsolatedService(intent, Context.BIND_AUTO_CREATE,
                Long.toString(SystemClock.uptimeMillis()), mContext.getMainExecutor(), conn));
        assertTrue("Timeout to bind to service " + intent.getComponent(),
                latch[0].await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS));
        return Pair.create(pid[0], conn);
    }

    /**
     * Make sure the screen state.
     */
Loading