• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.pm;
18 
19 import static android.Manifest.permission.QUERY_ALL_PACKAGES;
20 import static android.car.Car.PERMISSION_REGISTER_CAR_SYSTEM_UI_PROXY;
21 import static android.car.content.pm.CarPackageManager.ERROR_CODE_NO_PACKAGE;
22 import static android.car.content.pm.CarPackageManager.MANIFEST_METADATA_TARGET_CAR_VERSION;
23 import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
24 import static android.os.Process.INVALID_UID;
25 import static android.view.Display.DEFAULT_DISPLAY;
26 
27 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
28 
29 import static com.google.common.truth.Truth.assertThat;
30 import static com.google.common.truth.Truth.assertWithMessage;
31 
32 import static org.junit.Assert.assertThrows;
33 import static org.mockito.ArgumentMatchers.any;
34 import static org.mockito.ArgumentMatchers.anyBoolean;
35 import static org.mockito.ArgumentMatchers.anyInt;
36 import static org.mockito.ArgumentMatchers.eq;
37 import static org.mockito.Mockito.mock;
38 import static org.mockito.Mockito.spy;
39 import static org.mockito.Mockito.times;
40 import static org.mockito.Mockito.verify;
41 import static org.mockito.Mockito.when;
42 
43 import android.app.ActivityManager;
44 import android.app.PendingIntent;
45 import android.car.CarVersion;
46 import android.car.builtin.app.ActivityManagerHelper;
47 import android.car.content.pm.ICarBlockingUiCommandListener;
48 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
49 import android.content.Context;
50 import android.content.pm.ApplicationInfo;
51 import android.content.pm.PackageManager;
52 import android.content.pm.PackageManager.NameNotFoundException;
53 import android.os.Binder;
54 import android.os.Bundle;
55 import android.os.IBinder;
56 import android.os.Process;
57 import android.os.RemoteException;
58 import android.os.ServiceSpecificException;
59 import android.os.UserHandle;
60 
61 import androidx.test.ext.junit.runners.AndroidJUnit4;
62 import androidx.test.platform.app.InstrumentationRegistry;
63 
64 import com.android.car.CarOccupantZoneService;
65 import com.android.car.CarUxRestrictionsManagerService;
66 import com.android.car.am.CarActivityService;
67 
68 import org.junit.Before;
69 import org.junit.Test;
70 import org.junit.runner.RunWith;
71 import org.mockito.Mock;
72 
73 import java.util.ArrayList;
74 import java.util.HashMap;
75 import java.util.Map;
76 import java.util.Set;
77 
78 /**
79  * Unit tests for {@link CarPackageManagerService}.
80  */
81 @RunWith(AndroidJUnit4.class)
82 public class CarPackageManagerServiceUnitTest extends AbstractExtendedMockitoTestCase {
83     CarPackageManagerService mService;
84 
85     private Context mSpiedContext;
86     private PackageManager mSpiedPackageManager;
87 
88     private final UserHandle mUserHandle = UserHandle.of(666);
89 
90     @Mock
91     private Context mUserContext;
92 
93     @Mock
94     private CarUxRestrictionsManagerService mMockUxrService;
95     @Mock
96     private CarActivityService mMockActivityService;
97     @Mock
98     private CarOccupantZoneService mMockCarOccupantZoneService;
99     @Mock
100     private PendingIntent mMockPendingIntent;
101 
CarPackageManagerServiceUnitTest()102     public CarPackageManagerServiceUnitTest() {
103         super(CarPackageManagerService.TAG);
104     }
105 
106     @Override
onSessionBuilder(CustomMockitoSessionBuilder builder)107     protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
108         builder
109             .spyStatic(ActivityManagerHelper.class)
110             .spyStatic(Binder.class)
111             // Need to mock service itself because of getTargetCarVersion() - it doesn't make
112             // sense to test all variations of the methods that call it
113             .spyStatic(CarPackageManagerService.class);
114     }
115 
116     @Before
setUp()117     public void setUp() {
118         mSpiedContext = spy(InstrumentationRegistry.getInstrumentation().getContext());
119 
120         doReturn(mUserContext).when(mSpiedContext).createContextAsUser(mUserHandle, /* flags= */ 0);
121 
122         mSpiedPackageManager = spy(mSpiedContext.getPackageManager());
123         doReturn(mSpiedPackageManager).when(mSpiedContext).getPackageManager();
124 
125         mService = new CarPackageManagerService(mSpiedContext,
126                 mMockUxrService, mMockActivityService, mMockCarOccupantZoneService);
127     }
128 
129     @Test
testParseConfigList_SingleActivity()130     public void testParseConfigList_SingleActivity() {
131         String config = "com.android.test/.TestActivity";
132         Map<String, Set<String>> map = new HashMap<>();
133 
134         mService.parseConfigList(config, map);
135 
136         assertThat(map.get("com.android.test")).containsExactly(".TestActivity");
137     }
138 
139     @Test
testParseConfigList_Package()140     public void testParseConfigList_Package() {
141         String config = "com.android.test";
142         Map<String, Set<String>> map = new HashMap<>();
143 
144         mService.parseConfigList(config, map);
145 
146         assertThat(map.get("com.android.test")).isEmpty();
147     }
148 
149     @Test
testParseConfigList_MultipleActivities()150     public void testParseConfigList_MultipleActivities() {
151         String config = "com.android.test/.TestActivity0,com.android.test/.TestActivity1";
152         Map<String, Set<String>> map = new HashMap<>();
153 
154         mService.parseConfigList(config, map);
155 
156         assertThat(map.get("com.android.test")).containsExactly(".TestActivity0", ".TestActivity1");
157     }
158 
159     @Test
testParseConfigList_PackageAndActivity()160     public void testParseConfigList_PackageAndActivity() {
161         String config = "com.android.test/.TestActivity0,com.android.test";
162         Map<String, Set<String>> map = new HashMap<>();
163 
164         mService.parseConfigList(config, map);
165 
166         assertThat(map.get("com.android.test")).isEmpty();
167     }
168 
169     @Test
test_checkQueryPermission_noPermission()170     public void test_checkQueryPermission_noPermission() {
171         mockQueryPermission(false);
172 
173         assertThat(mService.callerCanQueryPackage("blah")).isFalse();
174     }
175 
176     @Test
test_checkQueryPermission_correctPermission()177     public void test_checkQueryPermission_correctPermission() {
178         mockQueryPermission(true);
179 
180         assertThat(mService.callerCanQueryPackage("blah")).isTrue();
181     }
182 
183     @Test
test_checkQueryPermission_samePackage()184     public void test_checkQueryPermission_samePackage() {
185         mockQueryPermission(false);
186 
187         assertThat(mService.callerCanQueryPackage(
188                 "com.android.car.carservice_unittest")).isTrue();
189     }
190 
191     @Test
testIsPendingIntentDistractionOptimised_withoutActivity()192     public void testIsPendingIntentDistractionOptimised_withoutActivity() {
193         when(mMockPendingIntent.isActivity()).thenReturn(false);
194 
195         assertThat(mService.isPendingIntentDistractionOptimized(mMockPendingIntent)).isFalse();
196     }
197 
198     @Test
testIsPendingIntentDistractionOptimised_noIntentComponents()199     public void testIsPendingIntentDistractionOptimised_noIntentComponents() {
200         when(mMockPendingIntent.isActivity()).thenReturn(true);
201         when(mMockPendingIntent.queryIntentComponents(MATCH_DEFAULT_ONLY)).thenReturn(
202                 new ArrayList<>());
203 
204         assertThat(mService.isPendingIntentDistractionOptimized(mMockPendingIntent)).isFalse();
205     }
206 
207     @Test
testGetTargetCarVersion_ok()208     public void testGetTargetCarVersion_ok() {
209         String pkgName = "dr.evil";
210         CarVersion Version = CarVersion.forMajorAndMinorVersions(66, 6);
211 
212         doReturn(Version)
213                 .when(() -> CarPackageManagerService.getTargetCarVersion(mUserContext, pkgName));
214 
215         mockCallingUser();
216 
217         assertWithMessage("getTargetCarVersion(%s)", pkgName)
218                 .that(mService.getTargetCarVersion(pkgName)).isSameInstanceAs(Version);
219     }
220 
221     @Test
testGetTargetCarVersion_byUser()222     public void testGetTargetCarVersion_byUser() {
223         String pkgName = "dr.evil";
224         CarVersion Version = CarVersion.forMajorAndMinorVersions(66, 6);
225 
226         doReturn(Version)
227                 .when(() -> CarPackageManagerService.getTargetCarVersion(mUserContext, pkgName));
228 
229         mockCallingUser();
230 
231         assertWithMessage("getTargetCarVersion(%s)", pkgName)
232                 .that(mService.getTargetCarVersion(mUserHandle, pkgName))
233                 .isSameInstanceAs(Version);
234     }
235 
236     @Test
testGetTargetCarVersion_self_ok()237     public void testGetTargetCarVersion_self_ok() throws Exception {
238         String pkgName = "dr.evil";
239         int myUid = Process.myUid();
240         doReturn(myUid).when(mSpiedPackageManager).getPackageUidAsUser(eq(pkgName), anyInt());
241         CarVersion Version = CarVersion.forMajorAndMinorVersions(66, 6);
242 
243         doReturn(Version)
244                 .when(() -> CarPackageManagerService.getTargetCarVersion(mUserContext, pkgName));
245 
246         mockCallingUser();
247 
248         assertWithMessage("getTargetCarVersion(%s)", pkgName)
249                 .that(mService.getSelfTargetCarVersion(pkgName)).isSameInstanceAs(Version);
250     }
251 
252     @Test
testGetTargetCarVersion_self_wrongUid()253     public void testGetTargetCarVersion_self_wrongUid() throws Exception {
254         int myUid = Process.myUid();
255         String pkgName = "dr.evil";
256         doReturn(INVALID_UID).when(mSpiedPackageManager).getPackageUidAsUser(eq(pkgName), anyInt());
257         CarVersion Version = CarVersion.forMajorAndMinorVersions(66, 6);
258 
259         doReturn(Version)
260                 .when(() -> CarPackageManagerService.getTargetCarVersion(mUserContext, pkgName));
261 
262         mockCallingUser();
263 
264         SecurityException e = assertThrows(SecurityException.class,
265                 () -> mService.getSelfTargetCarVersion(pkgName));
266 
267         String msg = e.getMessage();
268         assertWithMessage("exception message (pkg)").that(msg).contains(pkgName);
269         assertWithMessage("exception message (uid)").that(msg).contains(String.valueOf(myUid));
270     }
271 
272     @Test
testGetTargetCarVersion_static_null()273     public void testGetTargetCarVersion_static_null() {
274         assertThrows(NullPointerException.class,
275                 () -> CarPackageManagerService.getTargetCarVersion(mUserContext, null));
276     }
277 
278     @Test
testGetTargetCarVersion_static_noPermission()279     public void testGetTargetCarVersion_static_noPermission() {
280         mockQueryPermission(/* granted= */ false);
281 
282         assertThrows(SecurityException.class,
283                 () -> CarPackageManagerService.getTargetCarVersion(mUserContext, "d.oh"));
284     }
285 
286 
287     @Test
testGetTargetCarVersion_static_noApp()288     public void testGetTargetCarVersion_static_noApp() throws Exception {
289         mockQueryPermission(/* granted= */ true);
290         String causeMsg = mockGetApplicationInfoThrowsNotFound(mUserContext, "meaning.of.life");
291 
292         ServiceSpecificException e = assertThrows(ServiceSpecificException.class,
293                 () -> CarPackageManagerService.getTargetCarVersion(mUserContext,
294                         "meaning.of.life"));
295         assertWithMessage("exception code").that(e.errorCode).isEqualTo(ERROR_CODE_NO_PACKAGE);
296         assertWithMessage("exception msg").that(e.getMessage()).isEqualTo(causeMsg);
297     }
298 
299     // No need to test all scenarios, as they're tested by CarVersionParserParseMethodTest
300     @Test
testGetTargetCarVersion_static_ok()301     public void testGetTargetCarVersion_static_ok() throws Exception {
302         mockQueryPermission(/* granted= */ true);
303         ApplicationInfo info = mockGetApplicationInfo(mUserContext, "meaning.of.life");
304         info.targetSdkVersion = 666; // Set to make sure it's not used
305         info.metaData = new Bundle();
306         info.metaData.putString(MANIFEST_METADATA_TARGET_CAR_VERSION, "42:108");
307 
308         CarVersion actualVersion = CarPackageManagerService.getTargetCarVersion(
309                 mUserContext, "meaning.of.life");
310 
311         assertWithMessage("static getTargetCarVersion()").that(actualVersion).isNotNull();
312         assertWithMessage("major version").that(actualVersion.getMajorVersion()).isEqualTo(42);
313         assertWithMessage("minor version").that(actualVersion.getMinorVersion()).isEqualTo(108);
314     }
315 
mockQueryPermission(boolean granted)316     private void mockQueryPermission(boolean granted) {
317         int result = android.content.pm.PackageManager.PERMISSION_DENIED;
318         if (granted) {
319             result = android.content.pm.PackageManager.PERMISSION_GRANTED;
320         }
321         doReturn(result).when(() -> ActivityManagerHelper.checkComponentPermission(
322                 eq(QUERY_ALL_PACKAGES), anyInt(), anyInt(), anyBoolean()));
323         when(mUserContext.checkCallingOrSelfPermission(QUERY_ALL_PACKAGES)).thenReturn(result);
324     }
325 
mockCallingUser()326     private void mockCallingUser() {
327         doReturn(mUserHandle).when(() -> Binder.getCallingUserHandle());
328     }
329 
mockGetApplicationInfoThrowsNotFound(Context context, String packageName)330     private static String mockGetApplicationInfoThrowsNotFound(Context context, String packageName)
331             throws NameNotFoundException {
332         String msg = "D'OH!";
333         PackageManager pm = mock(PackageManager.class);
334         when(context.getPackageManager()).thenReturn(pm);
335         when(pm.getApplicationInfo(eq(packageName), any()))
336                 .thenThrow(new NameNotFoundException(msg));
337         return msg;
338     }
339 
mockGetApplicationInfo(Context context, String packageName)340     private static ApplicationInfo mockGetApplicationInfo(Context context, String packageName)
341             throws NameNotFoundException {
342         ApplicationInfo info = new ApplicationInfo();
343         PackageManager pm = mock(PackageManager.class);
344         when(context.getPackageManager()).thenReturn(pm);
345         when(pm.getApplicationInfo(eq(packageName), any())).thenReturn(info);
346         return info;
347     }
348 
349     @Test
registerBlockingUiCommandListenerThrowsException_withoutPermission()350     public void registerBlockingUiCommandListenerThrowsException_withoutPermission() {
351         applyPermission(PackageManager.PERMISSION_DENIED);
352         ICarBlockingUiCommandListener carBlockingUiCommandListener =
353                 setupBlockingUiCommandListener();
354 
355         assertThrows(SecurityException.class,
356                 () -> mService.registerBlockingUiCommandListener(
357                         carBlockingUiCommandListener, DEFAULT_DISPLAY));
358     }
359 
360     @Test
unregisterBlockingUiCommandListenerThrowsException_withoutPermission()361     public void unregisterBlockingUiCommandListenerThrowsException_withoutPermission() {
362         applyPermission(PackageManager.PERMISSION_DENIED);
363         ICarBlockingUiCommandListener carBlockingUiCommandListener =
364                 setupBlockingUiCommandListener();
365 
366         assertThrows(SecurityException.class,
367                 () -> mService.unregisterBlockingUiCommandListener(carBlockingUiCommandListener));
368     }
369 
370     @Test
registerBlockingUiCommandListener()371     public void registerBlockingUiCommandListener() {
372         applyPermission(PackageManager.PERMISSION_GRANTED);
373         ICarBlockingUiCommandListener carBlockingUiCommandListener =
374                 setupBlockingUiCommandListener();
375 
376         mService.registerBlockingUiCommandListener(carBlockingUiCommandListener, DEFAULT_DISPLAY);
377 
378         assertThat(mService.getCarBlockingUiCommandListenerRegisteredCallbacksForDisplay(
379                 DEFAULT_DISPLAY)).isEqualTo(1);
380     }
381 
382     @Test
unregisterBlockingUiCommandListener()383     public void unregisterBlockingUiCommandListener() {
384         applyPermission(PackageManager.PERMISSION_GRANTED);
385         ICarBlockingUiCommandListener carBlockingUiCommandListener =
386                 setupBlockingUiCommandListener();
387 
388         mService.registerBlockingUiCommandListener(carBlockingUiCommandListener, DEFAULT_DISPLAY);
389         mService.unregisterBlockingUiCommandListener(carBlockingUiCommandListener);
390 
391         assertThat(mService.getCarBlockingUiCommandListenerRegisteredCallbacksForDisplay(
392                 DEFAULT_DISPLAY)).isEqualTo(0);
393     }
394 
395     @Test
registerBlockingUiCommandListener_sameListenerNotRegisteredAgain()396     public void registerBlockingUiCommandListener_sameListenerNotRegisteredAgain() {
397         applyPermission(PackageManager.PERMISSION_GRANTED);
398         ICarBlockingUiCommandListener carBlockingUiCommandListener =
399                 setupBlockingUiCommandListener();
400 
401         mService.registerBlockingUiCommandListener(carBlockingUiCommandListener, DEFAULT_DISPLAY);
402         mService.registerBlockingUiCommandListener(carBlockingUiCommandListener, DEFAULT_DISPLAY);
403 
404         assertThat(mService.getCarBlockingUiCommandListenerRegisteredCallbacksForDisplay(
405                 DEFAULT_DISPLAY)).isEqualTo(1);
406     }
407 
408     @Test
registerBlockingUiCommandListener_registerMultipleListeners()409     public void registerBlockingUiCommandListener_registerMultipleListeners() {
410         applyPermission(PackageManager.PERMISSION_GRANTED);
411         ICarBlockingUiCommandListener carBlockingUiCommandListener1 =
412                 setupBlockingUiCommandListener();
413         ICarBlockingUiCommandListener carBlockingUiCommandListener2 =
414                 setupBlockingUiCommandListener();
415 
416         mService.registerBlockingUiCommandListener(carBlockingUiCommandListener1, DEFAULT_DISPLAY);
417         mService.registerBlockingUiCommandListener(carBlockingUiCommandListener2, DEFAULT_DISPLAY);
418 
419         assertThat(mService.getCarBlockingUiCommandListenerRegisteredCallbacksForDisplay(
420                 DEFAULT_DISPLAY)).isEqualTo(2);
421     }
422 
423     @Test
registerMultipleListeners_finishBlockingUiInvoked()424     public void registerMultipleListeners_finishBlockingUiInvoked()
425             throws RemoteException {
426         applyPermission(PackageManager.PERMISSION_GRANTED);
427         ICarBlockingUiCommandListener carBlockingUiCommandListener1 =
428                 setupBlockingUiCommandListener();
429         ICarBlockingUiCommandListener carBlockingUiCommandListener2 =
430                 setupBlockingUiCommandListener();
431         ActivityManager.RunningTaskInfo taskInfo = createTask();
432 
433         mService.registerBlockingUiCommandListener(carBlockingUiCommandListener1, DEFAULT_DISPLAY);
434         mService.registerBlockingUiCommandListener(carBlockingUiCommandListener2, DEFAULT_DISPLAY);
435         mService.finishBlockingUi(taskInfo);
436 
437         verify(carBlockingUiCommandListener1).finishBlockingUi();
438         verify(carBlockingUiCommandListener2).finishBlockingUi();
439     }
440 
441     @Test
registerListenerForOtherDisplay_finishBlockingUiNotInvoked()442     public void registerListenerForOtherDisplay_finishBlockingUiNotInvoked()
443             throws RemoteException {
444         applyPermission(PackageManager.PERMISSION_GRANTED);
445         ICarBlockingUiCommandListener carBlockingUiCommandListener =
446                 setupBlockingUiCommandListener();
447         ActivityManager.RunningTaskInfo taskInfo = createTask();
448         int tempDisplayId = 1;
449 
450         mService.registerBlockingUiCommandListener(carBlockingUiCommandListener, tempDisplayId);
451         mService.finishBlockingUi(taskInfo);
452 
453         verify(carBlockingUiCommandListener, times(0)).finishBlockingUi();
454     }
455 
456     @Test
registerMultipleListenersForDifferentDisplay_finishBlockingUiInvokedForSomeDisplay()457     public void registerMultipleListenersForDifferentDisplay_finishBlockingUiInvokedForSomeDisplay()
458             throws RemoteException {
459         applyPermission(PackageManager.PERMISSION_GRANTED);
460         ICarBlockingUiCommandListener carBlockingUiCommandListener1 =
461                 setupBlockingUiCommandListener();
462         ICarBlockingUiCommandListener carBlockingUiCommandListener2 =
463                 setupBlockingUiCommandListener();
464         ICarBlockingUiCommandListener carBlockingUiCommandListener3 =
465                 setupBlockingUiCommandListener();
466         ActivityManager.RunningTaskInfo taskInfo = createTask();
467         int tempDisplayId = 1;
468 
469         mService.registerBlockingUiCommandListener(carBlockingUiCommandListener1, DEFAULT_DISPLAY);
470         mService.registerBlockingUiCommandListener(carBlockingUiCommandListener2, DEFAULT_DISPLAY);
471         mService.registerBlockingUiCommandListener(carBlockingUiCommandListener3, tempDisplayId);
472         mService.finishBlockingUi(taskInfo);
473 
474         verify(carBlockingUiCommandListener1).finishBlockingUi();
475         verify(carBlockingUiCommandListener2).finishBlockingUi();
476         verify(carBlockingUiCommandListener3, times(0)).finishBlockingUi();
477     }
478 
createTask()479     private ActivityManager.RunningTaskInfo createTask() {
480         ActivityManager.RunningTaskInfo taskInfo =
481                 new ActivityManager.RunningTaskInfo();
482         taskInfo.taskId = 1;
483         taskInfo.displayId = DEFAULT_DISPLAY;
484         return taskInfo;
485     }
486 
setupBlockingUiCommandListener()487     private ICarBlockingUiCommandListener setupBlockingUiCommandListener() {
488         ICarBlockingUiCommandListener carBlockingUiCommandListener =
489                 mock(ICarBlockingUiCommandListener.class);
490         IBinder tempToken = new Binder();
491         when(carBlockingUiCommandListener.asBinder()).thenReturn(tempToken);
492         return carBlockingUiCommandListener;
493     }
494 
applyPermission(int permissionValue)495     private void applyPermission(int permissionValue) {
496         doReturn(permissionValue).when(mSpiedContext).checkCallingOrSelfPermission(
497                 PERMISSION_REGISTER_CAR_SYSTEM_UI_PROXY);
498     }
499 }
500