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

Commit f6fe73ad authored by Felipe Leme's avatar Felipe Leme
Browse files

Include activities launched on HSU on dumpsys user.

Bug: 412177078
Bug: 414326600
Test: adb shell dumpsys user --deprecated-calls
Flag: android.multiuser.hsu_allowlist_activities

Change-Id: I15625b5671b3ef23f3de621fd98aaa8562f84004
parent b59a4c08
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -452,3 +452,10 @@ flag {
     description: "For user restrictions about adding or editing shared or private Wi-Fi configurations"
     bug: "390240471"
}

flag {
     name: "hsu_allowlist_activities"
     namespace: "multiuser"
     description: "Adds an allowlist mechanism to decide which activities can be launched when the current user is the headless system user"
     bug: "412177078"
}
+45 −4
Original line number Diff line number Diff line
@@ -16,19 +16,22 @@
package com.android.server.pm;

import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.Process;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.SparseIntArray;

import com.android.server.LocalServices;

import java.io.PrintWriter;

// TODO(b/414326600): rename (and add unit tests) once it's used to log blocked HSU actions
// TODO(b/414326600): rename (and add unit tests) once the final design is ready (notice that it's
// also used to log UI actions on HSU
/**
 * Class used to report deprecated calls.
 */
@@ -36,7 +39,7 @@ final class MultiuserDeprecationReporter {

    private final Handler mHandler;

    // TODO(b/414326600): merge arrays below and/or use the proper proto / structure
    // TODO(b/414326600): merge collections below and/or use the proper proto / structure

    // Key is "absolute" uid  / app id (i.e., stripping out the user id part), value is count.
    @Nullable // Only set on debuggable builds
@@ -46,6 +49,10 @@ final class MultiuserDeprecationReporter {
    @Nullable // Only set on debuggable builds
    private final SparseIntArray mIsMainUserCalls;

    // Activities launched while the current user is the headless system user.
    @Nullable // Only set on debuggable builds
    private final ArraySet<ComponentName> mLaunchedHsuActivities;

    // Set on demand, Should not be used directly (but through getPackageManagerInternal() instead).
    @Nullable
    private PackageManagerInternal mPmInternal;
@@ -55,9 +62,11 @@ final class MultiuserDeprecationReporter {
        if (Build.isDebuggable()) {
            mGetMainUserCalls = new SparseIntArray();
            mIsMainUserCalls = new SparseIntArray();
            mLaunchedHsuActivities = new ArraySet<>();
        } else {
            mGetMainUserCalls = null;
            mIsMainUserCalls = null;
            mLaunchedHsuActivities = null;
        }
    }

@@ -86,6 +95,14 @@ final class MultiuserDeprecationReporter {
        });
    }

    // TODO(b/414326600): add unit tests (once the proper formats are determined).
    void logLaunchedHsuActivity(ComponentName activity) {
        if (mLaunchedHsuActivities == null) {
            return;
        }
        mHandler.post(() -> mLaunchedHsuActivities.add(activity));
    }

    // NOTE: output format might changed, so it should not be used for automated testing purposes
    // (a proto version will be provided when it's ready)
    void dump(PrintWriter pw) {
@@ -93,6 +110,8 @@ final class MultiuserDeprecationReporter {
        dump(pw, "getMainUser", mGetMainUserCalls);
        pw.println();
        dump(pw, "isMainUser", mIsMainUserCalls);
        pw.println();
        dumpLaunchedHsuActivities(pw);
    }

    private void dump(PrintWriter pw, String method, @Nullable SparseIntArray calls) {
@@ -125,6 +144,26 @@ final class MultiuserDeprecationReporter {
        }
    }

    private void dumpLaunchedHsuActivities(PrintWriter pw) {
        if (mLaunchedHsuActivities == null) {
            pw.println("Not logging launched HSU activities");
            return;
        }
        // TODO(b/414326600): should dump in the mHandler thread (as its state is written in that
        // thread), but it would require blocking the caller until it's done
        int size = mLaunchedHsuActivities.size();
        if (size == 0) {
            pw.println("Good News, Everyone!: no activity launched on HSU!");
            return;
        }
        // TODO(b/414326600): for now they're always launched, but once the allowlist mechanism is
        // implemented, it should print the real action
        pw.printf("%d activities launched on HSU:\n", size);
        for (int i = 0; i < size; i++) {
            pw.printf("  %s\n", mLaunchedHsuActivities.valueAt(i).flattenToShortString());
        }
    }

    // TODO(b/414326600): add unit tests
    void reset(PrintWriter pw) {
        // TODO(b/414326600): should reset in the mHandler thread (as its state is written in that
@@ -136,7 +175,9 @@ final class MultiuserDeprecationReporter {
        if (mIsMainUserCalls != null) {
            mIsMainUserCalls.clear();
        }

        if (mLaunchedHsuActivities != null) {
            mLaunchedHsuActivities.clear();
        }
        pw.println("Reset");
    }

+9 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SpecialUsers.CanBeNULL;
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.LauncherUserInfo;
import android.content.pm.UserInfo;
@@ -621,6 +622,14 @@ public abstract class UserManagerInternal {
     */
    public abstract @CanBeNULL @UserIdInt int getSupervisingProfileId();

    /** Optimized version of {@link UserManager#isHeadlessSystemUserMode()} */
    public abstract boolean isHeadlessSystemUserMode();

    // TODO(b/414326600): for now it's only logging launched activities, but once the allowlist
    // mechanism is implemented, it should pass some sort of @HsuUiActionResult int result
    /** Logs an activity launched in the headless system user */
    public abstract void logLaunchedHsuActivity(ComponentName activity);

    /**
     * Checks whether to show a notification for sounds (e.g., alarms, timers, etc.) from background
     * users.
+13 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ import android.app.StatsManager;
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
@@ -8088,6 +8089,7 @@ public class UserManagerService extends IUserManager.Stub {
                case "--visibility-mediator":
                    mUserVisibilityMediator.dump(pw, args);
                    return;
                // TODO(b/414326600): use a different arg for HSU SysUI actions
                case "--deprecated-calls":
                    if (args.length > 1 && args[1].equals("reset")) {
                        mDeprecationReporter.reset(pw);
@@ -8916,6 +8918,17 @@ public class UserManagerService extends IUserManager.Stub {
                }
            }
        }

        @Override
        public boolean isHeadlessSystemUserMode() {
            return UserManagerService.this.isHeadlessSystemUserMode();
        }

        @Override
        public void logLaunchedHsuActivity(ComponentName activity) {
            mDeprecationReporter.logLaunchedHsuActivity(activity);
        }

    } // class LocalService

    /**
+14 −0
Original line number Diff line number Diff line
@@ -1905,6 +1905,20 @@ class ActivityStarter {
                transition.setReady(started, false);
            }
        }

        if (android.multiuser.Flags.hsuAllowlistActivities()
                && isStarted && started.mUserId == UserHandle.USER_SYSTEM) {
            // TODO(b/412177078): for now we're just logging activities launched on HSU, but once
            // the allowlist mechanism is in place, we'll need to change this call to log a
            // successful launch, but also log when it's blocked earlier on (probably before the
            // check for voice session on executeRequest(), as voice interaction is not supported
            // on the HSU)
            var umi = mService.getUserManagerInternal();
            if (umi.isHeadlessSystemUserMode()) {
                umi.logLaunchedHsuActivity(started.mActivityComponent);
            }
        }

        return startedActivityRootTask;
    }