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

Commit 269ed2ba authored by Jackal Guo's avatar Jackal Guo Committed by Android (Google) Code Review
Browse files

Merge "Having an unified method for separated broadcasting"

parents 62661c1f 5f693a37
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.Manifest;
import android.annotation.AppIdInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.BroadcastOptions;
@@ -40,8 +41,10 @@ import android.content.pm.PackageInstaller;
import android.net.Uri;
import android.os.Bundle;
import android.os.PowerExemptionManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -49,6 +52,8 @@ import android.util.SparseArray;
import com.android.internal.util.ArrayUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Helper class to send broadcasts for various situations.
@@ -327,4 +332,45 @@ public final class BroadcastHelper {
        sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
                installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */, null);
    }

    /**
     * Get broadcast params list based on the given package and uid list. The broadcast params are
     * used to send broadcast separately if the given packages have different visibility allow list.
     *
     * @param pkgList The names of packages which have changes.
     * @param uidList The uids of packages which have changes.
     * @param userId The user where packages reside.
     * @return The list of {@link BroadcastParams} object.
     */
    public List<BroadcastParams> getBroadcastParams(@NonNull Computer snapshot,
            @NonNull String[] pkgList, @NonNull int[] uidList, @UserIdInt int userId) {
        final List<BroadcastParams> lists = new ArrayList<>(pkgList.length);
        // Get allow lists for the pkg in the pkgList. Merge into the existed pkgs and uids if
        // allow lists are the same.
        for (int i = 0; i < pkgList.length; i++) {
            final String pkgName = pkgList[i];
            final int uid = uidList[i];
            if (TextUtils.isEmpty(pkgName) || Process.INVALID_UID == uid) {
                continue;
            }
            int[] allowList = snapshot.getVisibilityAllowList(pkgName, userId);
            if (allowList == null) {
                allowList = new int[0];
            }
            boolean merged = false;
            for (int j = 0; j < lists.size(); j++) {
                final BroadcastParams list = lists.get(j);
                if (Arrays.equals(list.getAllowList().get(userId), allowList)) {
                    list.addPackage(pkgName, uid);
                    merged = true;
                    break;
                }
            }
            if (!merged) {
                lists.add(new BroadcastParams(pkgName, uid, allowList, userId));
            }
        }

        return lists;
    }
}
+96 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm;

import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.util.IntArray;
import android.util.SparseArray;

import com.android.internal.util.DataClass;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * A helper class that contains information about package names and uids that share the same allow
 * list for sending broadcasts. Used by various package helpers.
 */
@DataClass(genConstructor = false, genConstDefs = false)
final class BroadcastParams {
    private final @NonNull List<String> mPackageNames;
    private final @NonNull IntArray mUids;
    private final @NonNull SparseArray<int[]> mAllowList;

    BroadcastParams(@NonNull String packageName, @IntRange(from = 0) int uid,
            @NonNull int[] allowList, @UserIdInt int userId) {
        mPackageNames = new ArrayList<>(Arrays.asList(packageName));
        mUids = IntArray.wrap(new int[]{uid});
        mAllowList = new SparseArray<>(1);
        mAllowList.put(userId, allowList);
    }

    public void addPackage(@NonNull String packageName, @IntRange(from = 0) int uid) {
        mPackageNames.add(packageName);
        mUids.add(uid);
    }



    // Code below generated by codegen v1.0.23.
    //
    // DO NOT MODIFY!
    // CHECKSTYLE:OFF Generated code
    //
    // To regenerate run:
    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/BroadcastParams.java
    //
    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
    //   Settings > Editor > Code Style > Formatter Control
    //@formatter:off


    @DataClass.Generated.Member
    public @NonNull List<String> getPackageNames() {
        return mPackageNames;
    }

    @DataClass.Generated.Member
    public @NonNull IntArray getUids() {
        return mUids;
    }

    @DataClass.Generated.Member
    public @NonNull SparseArray<int[]> getAllowList() {
        return mAllowList;
    }

    @DataClass.Generated(
            time = 1651554793681L,
            codegenVersion = "1.0.23",
            sourceFile = "frameworks/base/services/core/java/com/android/server/pm/BroadcastParams.java",
            inputSignatures = "private final @android.annotation.NonNull java.util.List<java.lang.String> mPackageNames\nprivate final @android.annotation.NonNull android.util.IntArray mUids\nprivate final @android.annotation.NonNull android.util.SparseArray<int[]> mAllowList\npublic  void addPackage(java.lang.String,int)\nclass BroadcastParams extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
    @Deprecated
    private void __metadata() {}


    //@formatter:on
    // End of generated code

}
+9 −39
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.server.pm;

import static android.content.pm.PackageManager.RESTRICTION_NONE;
import static android.os.Process.SYSTEM_UID;

import android.annotation.NonNull;
import android.content.Intent;
@@ -34,7 +33,6 @@ import com.android.internal.util.ArrayUtils;
import com.android.server.pm.pkg.PackageStateInternal;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
@@ -186,50 +184,22 @@ public final class DistractingPackageHelper {
     */
    void sendDistractingPackagesChanged(@NonNull Computer snapshot, @NonNull String[] pkgList,
            int[] uidList, int userId, int distractionFlags) {
        final List<List<String>> pkgsToSend = new ArrayList(pkgList.length);
        final List<IntArray> uidsToSend = new ArrayList(pkgList.length);
        final List<SparseArray<int[]>> allowListsToSend = new ArrayList(pkgList.length);
        final int[] userIds = new int[] {userId};
        // Get allow lists for the pkg in the pkgList. Merge into the existed pkgs and uids if
        // allow lists are the same.
        for (int i = 0; i < pkgList.length; i++) {
            final String pkgName = pkgList[i];
            final int uid = uidList[i];
            SparseArray<int[]> allowList = mInjector.getAppsFilter().getVisibilityAllowList(
                    snapshot, snapshot.getPackageStateInternal(pkgName, SYSTEM_UID),
                    userIds, snapshot.getPackageStates());
            if (allowList == null) {
                allowList = new SparseArray<>(0);
            }
            boolean merged = false;
            for (int j = 0; j < allowListsToSend.size(); j++) {
                if (Arrays.equals(allowListsToSend.get(j).get(userId), allowList.get(userId))) {
                    pkgsToSend.get(j).add(pkgName);
                    uidsToSend.get(j).add(uid);
                    merged = true;
                    break;
                }
            }
            if (!merged) {
                pkgsToSend.add(new ArrayList<>(Arrays.asList(pkgName)));
                uidsToSend.add(IntArray.wrap(new int[] {uid}));
                allowListsToSend.add(allowList);
            }
        }

        final List<BroadcastParams> lists = mBroadcastHelper.getBroadcastParams(
                snapshot, pkgList, uidList, userId);
        final Handler handler = mInjector.getHandler();
        for (int i = 0; i < pkgsToSend.size(); i++) {
        for (int i = 0; i < lists.size(); i++) {
            final Bundle extras = new Bundle(3);
            final BroadcastParams list = lists.get(i);
            extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
                    pkgsToSend.get(i).toArray(new String[pkgsToSend.get(i).size()]));
            extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidsToSend.get(i).toArray());
                    list.getPackageNames().toArray(new String[0]));
            extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, list.getUids().toArray());
            extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, distractionFlags);
            final SparseArray<int[]> allowList = allowListsToSend.get(i).size() == 0
                    ? null : allowListsToSend.get(i);
            final SparseArray<int[]> allowList = list.getAllowList().size() == 0
                    ? null : list.getAllowList();
            handler.post(() -> mBroadcastHelper.sendPackageBroadcast(
                    Intent.ACTION_DISTRACTING_PACKAGES_CHANGED, null /* pkg */,
                    extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null /* targetPkg */,
                    null /* finishedReceiver */, userIds, null /* instantUserIds */,
                    null /* finishedReceiver */, new int[]{userId}, null /* instantUserIds */,
                    allowList, null /* bOptions */));
        }
    }
+9 −38
Original line number Diff line number Diff line
@@ -51,7 +51,6 @@ import com.android.server.pm.pkg.mutate.PackageUserStateWrite;
import com.android.server.utils.WatchedArrayMap;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
@@ -588,48 +587,20 @@ public final class SuspendPackageHelper {
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    void sendPackagesSuspendedForUser(@NonNull Computer snapshot, @NonNull String intent,
            @NonNull String[] pkgList, @NonNull int[] uidList, int userId) {
        final List<List<String>> pkgsToSend = new ArrayList(pkgList.length);
        final List<IntArray> uidsToSend = new ArrayList(pkgList.length);
        final List<SparseArray<int[]>> allowListsToSend = new ArrayList(pkgList.length);
        final int[] userIds = new int[] {userId};
        // Get allow lists for the pkg in the pkgList. Merge into the existed pkgs and uids if
        // allow lists are the same.
        for (int i = 0; i < pkgList.length; i++) {
            final String pkgName = pkgList[i];
            final int uid = uidList[i];
            SparseArray<int[]> allowList = mInjector.getAppsFilter().getVisibilityAllowList(
                    snapshot, snapshot.getPackageStateInternal(pkgName, SYSTEM_UID),
                    userIds, snapshot.getPackageStates());
            if (allowList == null) {
                allowList = new SparseArray<>(0);
            }
            boolean merged = false;
            for (int j = 0; j < allowListsToSend.size(); j++) {
                if (Arrays.equals(allowListsToSend.get(j).get(userId), allowList.get(userId))) {
                    pkgsToSend.get(j).add(pkgName);
                    uidsToSend.get(j).add(uid);
                    merged = true;
                    break;
                }
            }
            if (!merged) {
                pkgsToSend.add(new ArrayList<>(Arrays.asList(pkgName)));
                uidsToSend.add(IntArray.wrap(new int[] {uid}));
                allowListsToSend.add(allowList);
            }
        }

        final List<BroadcastParams> lists = mBroadcastHelper.getBroadcastParams(
                snapshot, pkgList, uidList, userId);
        final Handler handler = mInjector.getHandler();
        for (int i = 0; i < pkgsToSend.size(); i++) {
        for (int i = 0; i < lists.size(); i++) {
            final Bundle extras = new Bundle(3);
            final BroadcastParams list = lists.get(i);
            extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
                    pkgsToSend.get(i).toArray(new String[pkgsToSend.get(i).size()]));
            extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidsToSend.get(i).toArray());
            final SparseArray<int[]> allowList = allowListsToSend.get(i).size() == 0
                    ? null : allowListsToSend.get(i);
                    list.getPackageNames().toArray(new String[0]));
            extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, list.getUids().toArray());
            final SparseArray<int[]> allowList = list.getAllowList().size() == 0
                    ? null : list.getAllowList();
            handler.post(() -> mBroadcastHelper.sendPackageBroadcast(intent, null /* pkg */,
                    extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null /* targetPkg */,
                    null /* finishedReceiver */, userIds, null /* instantUserIds */,
                    null /* finishedReceiver */, new int[]{userId}, null /* instantUserIds */,
                    allowList, null /* bOptions */));
        }
    }
+117 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm

import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.MockitoAnnotations

@RunWith(JUnit4::class)
class BroadcastHelperTest {

    companion object {
        const val TEST_PACKAGE_1 = "com.android.test.package1"
        const val TEST_PACKAGE_2 = "com.android.test.package2"
        const val TEST_UID_1 = 10100
        const val TEST_UID_2 = 10101
        const val TEST_USER_ID = 0
    }

    lateinit var broadcastHelper: BroadcastHelper
    lateinit var packagesToChange: Array<String>
    lateinit var uidsToChange: IntArray

    @Mock
    lateinit var snapshot: Computer

    @Rule
    @JvmField
    val rule = MockSystemRule()

    @Before
    open fun setup() {
        MockitoAnnotations.initMocks(this)
        rule.system().stageNominalSystemState()
        broadcastHelper = BroadcastHelper(rule.mocks().injector)
        packagesToChange = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
        uidsToChange = intArrayOf(TEST_UID_1, TEST_UID_2)
    }

    @Test
    fun getBroadcastParams_withSameVisibilityAllowList_shouldGroup() {
        val allowList = intArrayOf(10001, 10002, 10003)
        mockVisibilityAllowList(TEST_PACKAGE_1, allowList)
        mockVisibilityAllowList(TEST_PACKAGE_2, allowList)

        val broadcastParams: List<BroadcastParams> = broadcastHelper.getBroadcastParams(
                snapshot, packagesToChange, uidsToChange, TEST_USER_ID)

        assertThat(broadcastParams).hasSize(1)
        assertThat(broadcastParams[0].packageNames).containsExactlyElementsIn(
                packagesToChange.toCollection(ArrayList()))
        assertThat(broadcastParams[0].uids.toArray()).asList().containsExactlyElementsIn(
                uidsToChange.toCollection(ArrayList()))
    }

    @Test
    fun getBroadcastParams_withDifferentVisibilityAllowList_shouldNotGroup() {
        val allowList1 = intArrayOf(10001, 10002, 10003)
        val allowList2 = intArrayOf(10001, 10002, 10007)
        mockVisibilityAllowList(TEST_PACKAGE_1, allowList1)
        mockVisibilityAllowList(TEST_PACKAGE_2, allowList2)

        val broadcastParams: List<BroadcastParams> = broadcastHelper.getBroadcastParams(
                snapshot, packagesToChange, uidsToChange, TEST_USER_ID)

        assertThat(broadcastParams).hasSize(2)
        broadcastParams.forEachIndexed { i, params ->
            val changedPackages = params.packageNames
            val changedUids = params.uids
            assertThat(changedPackages[0]).isEqualTo(packagesToChange[i])
            assertThat(changedUids[0]).isEqualTo(uidsToChange[i])
        }
    }

    @Test
    fun getBroadcastParams_withNullVisibilityAllowList_shouldNotGroup() {
        val allowList = intArrayOf(10001, 10002, 10003)
        mockVisibilityAllowList(TEST_PACKAGE_1, allowList)
        mockVisibilityAllowList(TEST_PACKAGE_2, null)

        val broadcastParams: List<BroadcastParams> = broadcastHelper.getBroadcastParams(
                snapshot, packagesToChange, uidsToChange, TEST_USER_ID)

        assertThat(broadcastParams).hasSize(2)
        broadcastParams.forEachIndexed { i, params ->
            val changedPackages = params.packageNames
            val changedUids = params.uids
            assertThat(changedPackages[0]).isEqualTo(packagesToChange[i])
            assertThat(changedUids[0]).isEqualTo(uidsToChange[i])
        }
    }

    private fun mockVisibilityAllowList(pkgName: String, list: IntArray?) {
        whenever(snapshot.getVisibilityAllowList(pkgName, TEST_USER_ID))
                .thenReturn(list ?: IntArray(0))
    }
}
 No newline at end of file
Loading