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

Commit 61d24a5a authored by Olivier Nshimiye's avatar Olivier Nshimiye Committed by Android (Google) Code Review
Browse files

Merge "Add an allowlist of private space apps to receive...

Merge "Add an allowlist of private space apps to receive (LOCKED_)BOOT_COMPLETED immediately" into main
parents 7cd80ed4 ed3f30f1
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -7554,4 +7554,11 @@

    <!-- The selection toolbar render service component name -->
    <string translatable="false" name="config_systemUiSelectionToolbarRenderService">com.android.systemui/.selectiontoolbar.app.service.SysUiSelectionToolbarRenderService</string>

    <!-- An allowlist of Private Space apps that should receive {@link android.intent.action.LOCKED_BOOT_COMPLETED}
     and {@link android.intent.action.BOOT_COMPLETED} intents immediately after private space gets
      unlocked instead of when these apps start. -->
    <string-array name="config_privateSpaceBootCompletedImmediateReceivers" translatable="false">
        <item>com.android.privatespace</item>
    </string-array>
</resources>
+3 −0
Original line number Diff line number Diff line
@@ -3398,6 +3398,9 @@
  <!-- Message shown in the dialog prompting the user to set up a screen lock to delete private space from Reset Options [CHAR LIMIT=120] -->
  <java-symbol type="string" name="private_space_set_up_screen_lock_for_reset" />

  <!-- Allowlist of private space apps to receive ACTION_(LOCKED_)BOOT_COMPLETED intents immediately -->
  <java-symbol type="array" name="config_privateSpaceBootCompletedImmediateReceivers" />

  <java-symbol type="string" name="deprecated_target_sdk_message" />
  <java-symbol type="string" name="deprecated_target_sdk_app_store" />

+27 −12
Original line number Diff line number Diff line
@@ -431,6 +431,7 @@ import com.android.internal.os.TransferPipe;
import com.android.internal.os.Zygote;
import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.policy.AttributeCache;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
@@ -5077,26 +5078,40 @@ public class ActivityManagerService extends IActivityManager.Stub
     */
    private void maybeSendBootCompletedLocked(ProcessRecord app, boolean isRestrictedBackupMode) {
        boolean sendBroadcast = false;
        if (android.os.Flags.allowPrivateProfile()
                && android.multiuser.Flags.enablePrivateSpaceFeatures()) {
        final UserManagerInternal umInternal =
                LocalServices.getService(UserManagerInternal.class);
        UserInfo userInfo = umInternal.getUserInfo(app.userId);
        String packageName = app.info.packageName;
        if (userInfo != null && userInfo.isPrivateProfile()) {
            // Packages in private space get deferred boot completed whenever they start the
            // first time since profile start
                if (!mPrivateSpaceBootCompletedPackages.contains(app.info.packageName)) {
                    mPrivateSpaceBootCompletedPackages.add(app.info.packageName);
            if (!mPrivateSpaceBootCompletedPackages.contains(packageName)) {
                // Skipping the apps that are allowlisted to receive LOCKED_BOOT_COMPLETED and
                // BOOT_COMPLETED immediately after the profile unlock
                if (android.multiuser.Flags.enableMovingContentIntoPrivateSpace()) {
                    String[] allowlistedPackages = mContext.getResources().getStringArray(
                            com.android.internal
                                    .R.array.config_privateSpaceBootCompletedImmediateReceivers);
                    if (!ArrayUtils.contains(allowlistedPackages, packageName)) {
                        mPrivateSpaceBootCompletedPackages.add(packageName);
                        sendBroadcast = true;
                    } else {
                        mPrivateSpaceBootCompletedPackages.addAll(List.of(allowlistedPackages));
                    }
                } else {
                    mPrivateSpaceBootCompletedPackages.add(packageName);
                    sendBroadcast = true;
                } // else, stopped packages in private space may still hit the logic below
                }
            }
            // else, stopped packages in private space may still hit the logic below
        }
        final boolean wasForceStopped = app.wasForceStopped()
                || app.getWindowProcessController().wasForceStopped();
        if (android.app.Flags.appRestrictionsApi() && wasForceStopped) {
            noteAppRestrictionEnabled(app.info.packageName, app.uid,
            noteAppRestrictionEnabled(packageName, app.uid,
                    RESTRICTION_LEVEL_FORCE_STOPPED, false,
                    RESTRICTION_REASON_USAGE, "unknown", RESTRICTION_SOURCE_USER, 0L);
        }
+95 −32
Original line number Diff line number Diff line
@@ -377,8 +377,6 @@ class UserController implements Handler.Callback {
    @GuardedBy("mLock")
    private boolean mIsBroadcastSentForSystemUserStarting;

    volatile boolean mBootCompleted;

    /**
     * In this mode, user is always stopped when switched out (unless overridden by the
     * {@code fw.stop_bg_users_on_switch} system property) but locking of user data is
@@ -717,19 +715,18 @@ class UserController implements Handler.Callback {
    }

    private void sendLockedBootCompletedBroadcast(IIntentReceiver receiver, @UserIdInt int userId) {
        if (android.os.Flags.allowPrivateProfile()
                && android.multiuser.Flags.enablePrivateSpaceFeatures()) {
            final UserInfo userInfo = getUserInfo(userId);
            if (userInfo != null && userInfo.isPrivateProfile()) {
                Slogf.i(TAG, "Skipping LOCKED_BOOT_COMPLETED for private profile user #" + userId);
                return;
            }
        }
        final Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
        intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
                | Intent.FLAG_RECEIVER_OFFLOAD
                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);

        final UserInfo userInfo = getUserInfo(userId);
        if (userInfo != null && userInfo.isPrivateProfile()) {
            sendBroadcastLockedBootCompleteForPrivateProfileApps(intent, userId, receiver);
            return;
        }

        mInjector.broadcastIntent(intent, null, receiver, 0, null, null,
                new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
                AppOpsManager.OP_NONE,
@@ -739,6 +736,44 @@ class UserController implements Handler.Callback {
                Binder.getCallingUid(), Binder.getCallingPid(), userId);
    }

    /**
     * Only broadcast the LOCKED_BOOT_COMPLETED intent to allowlisted immediate receivers. Other
     * packages will receive the intent after they are started.
     */
    private void sendBroadcastLockedBootCompleteForPrivateProfileApps(Intent bootIntent,
            int userId,
            IIntentReceiver receiver) {
        if (!android.multiuser.Flags.enableMovingContentIntoPrivateSpace()) {
            Slogf.i(TAG, "Skipping LOCKED_BOOT_COMPLETED for private profile user #" + userId);
            return;
        }

        String[] packages = mInjector.getContext().getResources().getStringArray(
                R.array.config_privateSpaceBootCompletedImmediateReceivers);

        AtomicInteger remainingPackages = new AtomicInteger(packages.length);
        for (String packageName : packages) {
            Intent intent = new Intent(bootIntent);
            intent.setPackage(packageName);
            IIntentReceiver packageReceiver = new IIntentReceiver.Stub() {
                @Override
                public void performReceive(Intent intent, int resultCode, String data,
                        Bundle extras, boolean ordered, boolean sticky, int sendingUser)
                        throws RemoteException {
                    if (remainingPackages.decrementAndGet() == 0) {
                        receiver.performReceive(intent, resultCode, data, extras, ordered, sticky,
                                sendingUser);
                    }
                }
            };
            mInjector.broadcastIntent(intent, null, packageReceiver, 0, null, null,
                    new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
                    AppOpsManager.OP_NONE, getTemporaryAppAllowlistBroadcastOptions(
                            REASON_LOCKED_BOOT_COMPLETED).toBundle(), false, MY_PID, SYSTEM_UID,
                    Binder.getCallingUid(), Binder.getCallingPid(), userId);
        }
    }

    /**
     * Step from {@link UserState#STATE_RUNNING_LOCKED} to
     * {@link UserState#STATE_RUNNING_UNLOCKING}.
@@ -931,13 +966,6 @@ class UserController implements Handler.Callback {

        mHandler.obtainMessage(USER_UNLOCKED_MSG, userId, 0).sendToTarget();

        if (android.os.Flags.allowPrivateProfile()
                && android.multiuser.Flags.enablePrivateSpaceFeatures()) {
            if (userInfo.isPrivateProfile()) {
                Slogf.i(TAG, "Skipping BOOT_COMPLETED for private profile user #" + userId);
                return;
            }
        }
        Slogf.i(TAG, "Posting BOOT_COMPLETED user #" + userId);
        // Do not report secondary users, runtime restarts or first boot/upgrade
        if (userId == UserHandle.USER_SYSTEM
@@ -956,23 +984,58 @@ class UserController implements Handler.Callback {
        // we also send the boot_completed broadcast from that thread.
        final int callingUid = Binder.getCallingUid();
        final int callingPid = Binder.getCallingPid();

        if (userInfo.isPrivateProfile()) {
            sendBroadcastBootCompleteForPrivateProfileApps(bootIntent, userId, callingUid,
                    callingPid);
            return;
        }
        FgThread.getHandler().post(() -> {
            broadcastBootCompletedIntent(bootIntent, userId, callingUid, callingPid);
        });
    }

    /**
     * Only broadcast the BOOT_COMPLETED intent to allowlisted immediate receivers. Other packages
     * will receive the intent after they are started.
     */
    private void sendBroadcastBootCompleteForPrivateProfileApps(Intent bootIntent, int userId,
            int callingUid, int callingPid) {
        if (!android.multiuser.Flags.enableMovingContentIntoPrivateSpace()) {
            Slogf.i(TAG, "Skipping BOOT_COMPLETED for private profile user #" + userId);
            return;
        }

        FgThread.getHandler().post(() -> {
            String[] packages = mInjector.getContext().getResources().getStringArray(
                    R.array.config_privateSpaceBootCompletedImmediateReceivers);

            for (String packageName : packages) {
                Intent intent = new Intent(bootIntent);
                intent.setPackage(packageName);
                broadcastBootCompletedIntent(intent, userId, callingUid, callingPid);
            }
        });
    }

    private void broadcastBootCompletedIntent(Intent bootIntent, int userId, int callingUid,
            int callingPid) {
        mInjector.broadcastIntent(bootIntent, null,
                new IIntentReceiver.Stub() {
                    @Override
                    public void performReceive(Intent intent, int resultCode, String data,
                            Bundle extras, boolean ordered, boolean sticky, int sendingUser)
                            throws RemoteException {
                            Slogf.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u"
                                    + userId);
                            mBootCompleted = true;
                        Slogf.i(UserController.TAG,
                                "Finished processing BOOT_COMPLETED for u" + userId
                                        + (Objects.isNull(bootIntent.getPackage()) ? ""
                                        : ", package: " + bootIntent.getPackage()));
                    }
                }, 0, null, null,
                new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
                AppOpsManager.OP_NONE,
                getTemporaryAppAllowlistBroadcastOptions(REASON_BOOT_COMPLETED).toBundle(),
                false, MY_PID, SYSTEM_UID, callingUid, callingPid, userId);
        });
    }

    /**