Loading core/java/android/content/pm/multiuser.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -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" } services/core/java/com/android/server/pm/MultiuserDeprecationReporter.java +45 −4 Original line number Diff line number Diff line Loading @@ -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. */ Loading @@ -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 Loading @@ -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; Loading @@ -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; } } Loading Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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 Loading @@ -136,7 +175,9 @@ final class MultiuserDeprecationReporter { if (mIsMainUserCalls != null) { mIsMainUserCalls.clear(); } if (mLaunchedHsuActivities != null) { mLaunchedHsuActivities.clear(); } pw.println("Reset"); } Loading services/core/java/com/android/server/pm/UserManagerInternal.java +9 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading services/core/java/com/android/server/pm/UserManagerService.java +13 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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 /** Loading services/core/java/com/android/server/wm/ActivityStarter.java +14 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading
core/java/android/content/pm/multiuser.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -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" }
services/core/java/com/android/server/pm/MultiuserDeprecationReporter.java +45 −4 Original line number Diff line number Diff line Loading @@ -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. */ Loading @@ -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 Loading @@ -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; Loading @@ -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; } } Loading Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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 Loading @@ -136,7 +175,9 @@ final class MultiuserDeprecationReporter { if (mIsMainUserCalls != null) { mIsMainUserCalls.clear(); } if (mLaunchedHsuActivities != null) { mLaunchedHsuActivities.clear(); } pw.println("Reset"); } Loading
services/core/java/com/android/server/pm/UserManagerInternal.java +9 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading
services/core/java/com/android/server/pm/UserManagerService.java +13 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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 /** Loading
services/core/java/com/android/server/wm/ActivityStarter.java +14 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading