summaryrefslogtreecommitdiff
path: root/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
blob: f44104e10967f00b2c96fd98d408dcedbd0bc4fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/*
 * Copyright (C) 2018 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.am;

import static org.junit.Assert.assertNull;

import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.os.Process;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;

import androidx.test.filters.SmallTest;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Test class for {@link BroadcastRecord}.
 *
 * Build/Install/Run:
 *  atest FrameworksServicesTests:BroadcastRecordTest
 */
@SmallTest
@Presubmit
public class BroadcastRecordTest {

    @Test
    public void testCleanupDisabledPackageReceivers() {
        final int user0 = UserHandle.USER_SYSTEM;
        final int user1 = user0 + 1;
        final String pkgToCleanup = "pkg.a";
        final String pkgOther = "pkg.b";

        // Receivers contain multiple-user (contains [pkg.a@u0, pkg.a@u1, pkg.b@u0, pkg.b@u1]).
        final List<ResolveInfo> receiversM = createReceiverInfos(
                new String[] { pkgToCleanup, pkgOther },
                new int[] { user0, user1 });
        // Receivers only contain one user (contains [pkg.a@u0, pkg.b@u0]).
        final List<ResolveInfo> receiversU0 = excludeReceivers(
                receiversM, null /* packageName */, user1);

        // With given package:
        // Send to all users, cleanup a package of all users.
        final BroadcastRecord recordAllAll = createBroadcastRecord(receiversM, UserHandle.USER_ALL);
        cleanupDisabledPackageReceivers(recordAllAll, pkgToCleanup, UserHandle.USER_ALL);
        assertNull(verifyRemaining(recordAllAll, excludeReceivers(receiversM, pkgToCleanup, -1)));

        // Send to all users, cleanup a package of one user.
        final BroadcastRecord recordAllOne = createBroadcastRecord(receiversM, UserHandle.USER_ALL);
        cleanupDisabledPackageReceivers(recordAllOne, pkgToCleanup, user0);
        assertNull(verifyRemaining(recordAllOne,
                excludeReceivers(receiversM, pkgToCleanup, user0)));

        // Send to one user, cleanup a package of all users.
        final BroadcastRecord recordOneAll = createBroadcastRecord(receiversU0, user0);
        cleanupDisabledPackageReceivers(recordOneAll, pkgToCleanup, UserHandle.USER_ALL);
        assertNull(verifyRemaining(recordOneAll, excludeReceivers(receiversU0, pkgToCleanup, -1)));

        // Send to one user, cleanup a package one user.
        final BroadcastRecord recordOneOne = createBroadcastRecord(receiversU0, user0);
        cleanupDisabledPackageReceivers(recordOneOne, pkgToCleanup, user0);
        assertNull(verifyRemaining(recordOneOne, excludeReceivers(receiversU0, pkgToCleanup, -1)));

        // Without given package (e.g. stop user):
        // Send to all users, cleanup one user.
        final BroadcastRecord recordAllM = createBroadcastRecord(receiversM, UserHandle.USER_ALL);
        cleanupDisabledPackageReceivers(recordAllM, null /* packageName */, user1);
        assertNull(verifyRemaining(recordAllM,
                excludeReceivers(receiversM, null /* packageName */, user1)));

        // Send to one user, cleanup one user.
        final BroadcastRecord recordU0 = createBroadcastRecord(receiversU0, user0);
        cleanupDisabledPackageReceivers(recordU0, null /* packageName */, user0);
        assertNull(verifyRemaining(recordU0, Collections.emptyList()));
    }

    private static void cleanupDisabledPackageReceivers(BroadcastRecord record,
            String packageName, int userId) {
        record.cleanupDisabledPackageReceiversLocked(packageName, null /* filterByClasses */,
                userId, true /* doit */);
    }

    private static String verifyRemaining(BroadcastRecord record,
            List<ResolveInfo> expectedRemainingReceivers) {
        final StringBuilder errorMsg = new StringBuilder();

        for (final Object receiver : record.receivers) {
            final ResolveInfo resolveInfo = (ResolveInfo) receiver;
            final ApplicationInfo appInfo = resolveInfo.activityInfo.applicationInfo;

            boolean foundExpected = false;
            for (final ResolveInfo expectedReceiver : expectedRemainingReceivers) {
                final ApplicationInfo expectedAppInfo =
                        expectedReceiver.activityInfo.applicationInfo;
                if (appInfo.packageName.equals(expectedAppInfo.packageName)
                        && UserHandle.getUserId(appInfo.uid) == UserHandle
                                .getUserId(expectedAppInfo.uid)) {
                    foundExpected = true;
                    break;
                }
            }
            if (!foundExpected) {
                errorMsg.append(appInfo.packageName).append("@")
                        .append('u').append(UserHandle.getUserId(appInfo.uid)).append(' ');
            }
        }

        return errorMsg.length() == 0 ? null
                : errorMsg.insert(0, "Contains unexpected receiver: ").toString();
    }

    private static ResolveInfo createResolveInfo(String packageName, int uid) {
        final ResolveInfo resolveInfo = new ResolveInfo();
        final ActivityInfo activityInfo = new ActivityInfo();
        final ApplicationInfo appInfo = new ApplicationInfo();
        appInfo.packageName = packageName;
        appInfo.uid = uid;
        activityInfo.applicationInfo = appInfo;
        resolveInfo.activityInfo = activityInfo;
        return resolveInfo;
    }

    /**
     * Generate (packages.length * userIds.length) receivers.
     */
    private static List<ResolveInfo> createReceiverInfos(String[] packages, int[] userIds) {
        final List<ResolveInfo> receivers = new ArrayList<>();
        for (int i = 0; i < packages.length; i++) {
            for (final int userId : userIds) {
                receivers.add(createResolveInfo(packages[i],
                        UserHandle.getUid(userId, Process.FIRST_APPLICATION_UID + i)));
            }
        }
        return receivers;
    }

    /**
     * Create a new list which filters out item if package name or user id is matched.
     * Null package name or user id < 0 will be considered as don't care.
     */
    private static List<ResolveInfo> excludeReceivers(List<ResolveInfo> receivers,
            String packageName, int userId) {
        final List<ResolveInfo> excludedList = new ArrayList<>();
        for (final ResolveInfo receiver : receivers) {
            if ((packageName != null
                    && !packageName.equals(receiver.activityInfo.applicationInfo.packageName))
                    || (userId > -1 && userId != UserHandle
                            .getUserId(receiver.activityInfo.applicationInfo.uid))) {
                excludedList.add(receiver);
            }
        }
        return excludedList;
    }

    private static BroadcastRecord createBroadcastRecord(List<ResolveInfo> receivers, int userId) {
        return new BroadcastRecord(
                null /* queue */,
                new Intent(),
                null /* callerApp */,
                null  /* callerPackage */,
                null /* callerFeatureId */,
                0 /* callingPid */,
                0 /* callingUid */,
                false /* callerInstantApp */,
                null /* resolvedType */,
                null /* requiredPermissions */,
                null /* excludedPermissions */,
                null /* excludedPackages */,
                0 /* appOp */,
                null /* options */,
                new ArrayList<>(receivers), // Make a copy to not affect the original list.
                null /* resultTo */,
                0 /* resultCode */,
                null /* resultData */,
                null /* resultExtras */,
                false /* serialized */,
                false /* sticky */,
                false /* initialSticky */,
                userId,
                false /* allowBackgroundActivityStarts */,
                null /* activityStartsToken */,
                false /* timeoutExempt */ );
    }
}