1 /*
2  * Copyright (C) 2022 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.server.location;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertThrows;
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.ArgumentMatchers.anyInt;
24 import static org.mockito.ArgumentMatchers.anyString;
25 import static org.mockito.Mockito.doReturn;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.MockitoAnnotations.initMocks;
28 
29 import android.app.AppOpsManager;
30 import android.content.Context;
31 import android.content.pm.PackageManager;
32 import android.content.res.Resources;
33 import android.location.ILocationListener;
34 import android.location.LocationManagerInternal;
35 import android.location.LocationRequest;
36 import android.location.provider.ProviderRequest;
37 import android.os.IBinder;
38 import android.os.PowerManager;
39 import android.platform.test.annotations.Presubmit;
40 
41 import androidx.test.ext.junit.runners.AndroidJUnit4;
42 import androidx.test.filters.SmallTest;
43 import androidx.test.platform.app.InstrumentationRegistry;
44 
45 import com.android.server.LocalServices;
46 import com.android.server.location.injector.FakeUserInfoHelper;
47 import com.android.server.location.injector.TestInjector;
48 import com.android.server.location.provider.AbstractLocationProvider;
49 import com.android.server.location.provider.LocationProviderManager;
50 import com.android.server.pm.permission.LegacyPermissionManagerInternal;
51 
52 import com.google.common.util.concurrent.MoreExecutors;
53 
54 import org.junit.After;
55 import org.junit.Before;
56 import org.junit.Ignore;
57 import org.junit.Test;
58 import org.junit.runner.RunWith;
59 import org.mockito.Mock;
60 import org.mockito.Spy;
61 
62 import java.util.Collections;
63 
64 @Presubmit
65 @SmallTest
66 @RunWith(AndroidJUnit4.class)
67 public class LocationManagerServiceTest {
68     private static final String PROVIDER_WITH_PERMISSION = "provider_with_permission";
69     private static final String PROVIDER_WITHOUT_PERMISSION = "provider_without_permission";
70     private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID;
71     private static final String CALLER_PACKAGE = "caller_package";
72     private static final String MISSING_PERMISSION = "missing_permission";
73     private static final String ATTRIBUTION_TAG = "test_tag";
74 
75     private TestInjector mInjector;
76     private LocationManagerService mLocationManagerService;
77 
78     @Spy private FakeAbstractLocationProvider mProviderWithPermission;
79     @Spy private FakeAbstractLocationProvider mProviderWithoutPermission;
80     @Mock private ILocationListener mLocationListener;
81     @Mock private IBinder mBinder;
82     @Mock private Context mContext;
83     @Mock private Resources mResources;
84     @Mock private PackageManager mPackageManager;
85     @Mock private AppOpsManager mAppOpsManager;
86     @Mock private PowerManager mPowerManager;
87     @Mock private PowerManager.WakeLock mWakeLock;
88     @Mock private LegacyPermissionManagerInternal mPermissionManagerInternal;
89 
90     @Before
setUp()91     public void setUp() {
92         initMocks(this);
93 
94         doReturn(mContext).when(mContext).createAttributionContext(any());
95         doReturn("android").when(mContext).getPackageName();
96         doReturn(mResources).when(mContext).getResources();
97         doReturn(mPackageManager).when(mContext).getPackageManager();
98         doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
99         doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
100         doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
101         String[] packages = {CALLER_PACKAGE};
102         doReturn(InstrumentationRegistry.getInstrumentation().getContext().getContentResolver())
103                 .when(mContext)
104                 .getContentResolver();
105         doReturn(packages).when(mPackageManager).getPackagesForUid(anyInt());
106         doReturn(mBinder).when(mLocationListener).asBinder();
107         doReturn(PackageManager.PERMISSION_DENIED)
108                 .when(mContext)
109                 .checkCallingOrSelfPermission(MISSING_PERMISSION);
110 
111         mInjector = new TestInjector(mContext);
112         mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, true);
113 
114         LocalServices.addService(LegacyPermissionManagerInternal.class, mPermissionManagerInternal);
115 
116         mLocationManagerService = new LocationManagerService(mContext, mInjector);
117 
118         LocationProviderManager managerWithPermission =
119                 new LocationProviderManager(
120                         mContext, mInjector, PROVIDER_WITH_PERMISSION, /* passiveManager= */ null);
121         mLocationManagerService.addLocationProviderManager(
122                 managerWithPermission, mProviderWithPermission);
123         LocationProviderManager managerWithoutPermission =
124                 new LocationProviderManager(
125                         mContext,
126                         mInjector,
127                         PROVIDER_WITHOUT_PERMISSION,
128                         /* passiveManager= */ null,
129                         Collections.singletonList(MISSING_PERMISSION));
130         mLocationManagerService.addLocationProviderManager(
131                 managerWithoutPermission, mProviderWithoutPermission);
132     }
133 
134     @After
tearDown()135     public void tearDown() throws Exception {
136         LocalServices.removeServiceForTest(LegacyPermissionManagerInternal.class);
137         LocalServices.removeServiceForTest(LocationManagerInternal.class);
138     }
139 
140     @Test
141     @Ignore("b/274432939") // Test is flaky for as of yet unknown reasons
testRequestLocationUpdates()142     public void testRequestLocationUpdates() {
143         LocationRequest request = new LocationRequest.Builder(0).build();
144         mLocationManagerService.registerLocationListener(
145                 PROVIDER_WITH_PERMISSION,
146                 request,
147                 mLocationListener,
148                 CALLER_PACKAGE,
149                 ATTRIBUTION_TAG,
150                 "any_listener_id");
151         verify(mProviderWithPermission).onSetRequestPublic(any());
152     }
153 
154     @Test
testRequestLocationUpdates_noPermission()155     public void testRequestLocationUpdates_noPermission() {
156         LocationRequest request = new LocationRequest.Builder(0).build();
157         assertThrows(
158                 IllegalArgumentException.class,
159                 () ->
160                         mLocationManagerService.registerLocationListener(
161                                 PROVIDER_WITHOUT_PERMISSION,
162                                 request,
163                                 mLocationListener,
164                                 CALLER_PACKAGE,
165                                 ATTRIBUTION_TAG,
166                                 "any_listener_id"));
167     }
168 
169     @Test
testHasProvider()170     public void testHasProvider() {
171         assertThat(mLocationManagerService.hasProvider(PROVIDER_WITH_PERMISSION)).isTrue();
172     }
173 
174     @Test
testHasProvider_noPermission()175     public void testHasProvider_noPermission() {
176         assertThat(mLocationManagerService.hasProvider(PROVIDER_WITHOUT_PERMISSION)).isFalse();
177     }
178 
179     @Test
testGetAllProviders()180     public void testGetAllProviders() {
181         assertThat(mLocationManagerService.getAllProviders()).contains(PROVIDER_WITH_PERMISSION);
182         assertThat(mLocationManagerService.getAllProviders())
183                 .doesNotContain(PROVIDER_WITHOUT_PERMISSION);
184     }
185 
186     abstract static class FakeAbstractLocationProvider extends AbstractLocationProvider {
FakeAbstractLocationProvider()187         FakeAbstractLocationProvider() {
188             super(
189                     MoreExecutors.directExecutor(),
190                     /* identity= */ null,
191                     /* properties= */ null,
192                     /* extraAttributionTags= */ Collections.emptySet());
193             setAllowed(true);
194         }
195 
196         @Override
onSetRequest(ProviderRequest request)197         protected void onSetRequest(ProviderRequest request) {
198             // Call a public version of this method so mockito can verify.
199             onSetRequestPublic(request);
200         }
201 
onSetRequestPublic(ProviderRequest request)202         public abstract void onSetRequestPublic(ProviderRequest request);
203     }
204 }
205