1 /*
2  * Copyright (C) 2020 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.vcn;
18 
19 import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
20 import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
21 import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
22 import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
23 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
24 import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
25 
26 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
27 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
28 
29 import static org.junit.Assert.assertEquals;
30 import static org.junit.Assert.assertNotNull;
31 import static org.junit.Assert.assertNull;
32 import static org.junit.Assert.assertTrue;
33 import static org.mockito.ArgumentMatchers.any;
34 import static org.mockito.ArgumentMatchers.anyInt;
35 import static org.mockito.ArgumentMatchers.argThat;
36 import static org.mockito.ArgumentMatchers.eq;
37 import static org.mockito.Mockito.doReturn;
38 import static org.mockito.Mockito.mock;
39 import static org.mockito.Mockito.verify;
40 import static org.mockito.Mockito.verifyNoMoreInteractions;
41 
42 import static java.util.Collections.emptyMap;
43 import static java.util.Collections.emptySet;
44 import static java.util.Collections.singletonMap;
45 
46 import android.annotation.NonNull;
47 import android.content.Context;
48 import android.content.Intent;
49 import android.content.IntentFilter;
50 import android.os.Handler;
51 import android.os.HandlerExecutor;
52 import android.os.ParcelUuid;
53 import android.os.test.TestLooper;
54 import android.telephony.CarrierConfigManager;
55 import android.telephony.SubscriptionInfo;
56 import android.telephony.SubscriptionManager;
57 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
58 import android.telephony.TelephonyCallback;
59 import android.telephony.TelephonyManager;
60 import android.util.ArraySet;
61 
62 import androidx.test.filters.SmallTest;
63 import androidx.test.runner.AndroidJUnit4;
64 
65 import org.junit.Before;
66 import org.junit.Test;
67 import org.junit.runner.RunWith;
68 import org.mockito.ArgumentCaptor;
69 
70 import java.util.ArrayList;
71 import java.util.Arrays;
72 import java.util.Collections;
73 import java.util.HashMap;
74 import java.util.List;
75 import java.util.Map;
76 import java.util.Set;
77 import java.util.UUID;
78 
79 /** Tests for TelephonySubscriptionTracker */
80 @RunWith(AndroidJUnit4.class)
81 @SmallTest
82 public class TelephonySubscriptionTrackerTest {
83     private static final String PACKAGE_NAME =
84             TelephonySubscriptionTrackerTest.class.getPackage().getName();
85     private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID());
86     private static final int TEST_SIM_SLOT_INDEX = 1;
87     private static final int TEST_SUBSCRIPTION_ID_1 = 2;
88     private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class);
89     private static final int TEST_SUBSCRIPTION_ID_2 = 3;
90     private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
91     private static final Map<ParcelUuid, Set<String>> TEST_PRIVILEGED_PACKAGES =
92             Collections.singletonMap(TEST_PARCEL_UUID, Collections.singleton(PACKAGE_NAME));
93     private static final Map<Integer, SubscriptionInfo> TEST_SUBID_TO_INFO_MAP;
94 
95     static {
96         final Map<Integer, SubscriptionInfo> subIdToGroupMap = new HashMap<>();
subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_SUBINFO_1)97         subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_SUBINFO_1);
subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_SUBINFO_2)98         subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_SUBINFO_2);
99         TEST_SUBID_TO_INFO_MAP = Collections.unmodifiableMap(subIdToGroupMap);
100     }
101 
102     @NonNull private final Context mContext;
103     @NonNull private final TestLooper mTestLooper;
104     @NonNull private final Handler mHandler;
105     @NonNull private final TelephonySubscriptionTracker.Dependencies mDeps;
106 
107     @NonNull private final TelephonyManager mTelephonyManager;
108     @NonNull private final SubscriptionManager mSubscriptionManager;
109     @NonNull private final CarrierConfigManager mCarrierConfigManager;
110 
111     @NonNull private TelephonySubscriptionTrackerCallback mCallback;
112     @NonNull private TelephonySubscriptionTracker mTelephonySubscriptionTracker;
113 
TelephonySubscriptionTrackerTest()114     public TelephonySubscriptionTrackerTest() {
115         mContext = mock(Context.class);
116         mTestLooper = new TestLooper();
117         mHandler = new Handler(mTestLooper.getLooper());
118         mDeps = mock(TelephonySubscriptionTracker.Dependencies.class);
119 
120         mTelephonyManager = mock(TelephonyManager.class);
121         mSubscriptionManager = mock(SubscriptionManager.class);
122         mCarrierConfigManager = mock(CarrierConfigManager.class);
123 
124         doReturn(Context.TELEPHONY_SERVICE)
125                 .when(mContext)
126                 .getSystemServiceName(TelephonyManager.class);
127         doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE);
128 
129         doReturn(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
130                 .when(mContext)
131                 .getSystemServiceName(SubscriptionManager.class);
132         doReturn(mSubscriptionManager)
133                 .when(mContext)
134                 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
135 
136         doReturn(Context.CARRIER_CONFIG_SERVICE)
137                 .when(mContext)
138                 .getSystemServiceName(CarrierConfigManager.class);
139         doReturn(mCarrierConfigManager)
140                 .when(mContext)
141                 .getSystemService(Context.CARRIER_CONFIG_SERVICE);
142 
143         // subId 1, 2 are in same subGrp, only subId 1 is active
144         doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_1).getGroupUuid();
145         doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_2).getGroupUuid();
146         doReturn(TEST_SIM_SLOT_INDEX).when(TEST_SUBINFO_1).getSimSlotIndex();
147         doReturn(INVALID_SIM_SLOT_INDEX).when(TEST_SUBINFO_2).getSimSlotIndex();
148         doReturn(TEST_SUBSCRIPTION_ID_1).when(TEST_SUBINFO_1).getSubscriptionId();
149         doReturn(TEST_SUBSCRIPTION_ID_2).when(TEST_SUBINFO_2).getSubscriptionId();
150     }
151 
152     @Before
setUp()153     public void setUp() throws Exception {
154         mCallback = mock(TelephonySubscriptionTrackerCallback.class);
155         mTelephonySubscriptionTracker =
156                 new TelephonySubscriptionTracker(mContext, mHandler, mCallback, mDeps);
157         mTelephonySubscriptionTracker.register();
158 
159         doReturn(true).when(mDeps).isConfigForIdentifiedCarrier(any());
160         doReturn(Arrays.asList(TEST_SUBINFO_1, TEST_SUBINFO_2))
161                 .when(mSubscriptionManager)
162                 .getAllSubscriptionInfoList();
163 
164         doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
165         setPrivilegedPackagesForMock(Collections.singletonList(PACKAGE_NAME));
166     }
167 
getIntentFilter()168     private IntentFilter getIntentFilter() {
169         final ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
170         verify(mContext).registerReceiver(any(), captor.capture(), any(), any());
171 
172         return captor.getValue();
173     }
174 
getOnSubscriptionsChangedListener()175     private OnSubscriptionsChangedListener getOnSubscriptionsChangedListener() {
176         final ArgumentCaptor<OnSubscriptionsChangedListener> captor =
177                 ArgumentCaptor.forClass(OnSubscriptionsChangedListener.class);
178         verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), captor.capture());
179 
180         return captor.getValue();
181     }
182 
getActiveDataSubscriptionIdListener()183     private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() {
184         final ArgumentCaptor<TelephonyCallback> captor =
185                 ArgumentCaptor.forClass(TelephonyCallback.class);
186         verify(mTelephonyManager).registerTelephonyCallback(any(), captor.capture());
187 
188         return (ActiveDataSubscriptionIdListener) captor.getValue();
189     }
190 
buildTestBroadcastIntent(boolean hasValidSubscription)191     private Intent buildTestBroadcastIntent(boolean hasValidSubscription) {
192         Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED);
193         intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX);
194         intent.putExtra(
195                 EXTRA_SUBSCRIPTION_INDEX,
196                 hasValidSubscription ? TEST_SUBSCRIPTION_ID_1 : INVALID_SUBSCRIPTION_ID);
197 
198         return intent;
199     }
200 
buildExpectedSnapshot( Map<ParcelUuid, Set<String>> privilegedPackages)201     private TelephonySubscriptionSnapshot buildExpectedSnapshot(
202             Map<ParcelUuid, Set<String>> privilegedPackages) {
203         return buildExpectedSnapshot(TEST_SUBID_TO_INFO_MAP, privilegedPackages);
204     }
205 
buildExpectedSnapshot( Map<Integer, SubscriptionInfo> subIdToInfoMap, Map<ParcelUuid, Set<String>> privilegedPackages)206     private TelephonySubscriptionSnapshot buildExpectedSnapshot(
207             Map<Integer, SubscriptionInfo> subIdToInfoMap,
208             Map<ParcelUuid, Set<String>> privilegedPackages) {
209         return new TelephonySubscriptionSnapshot(0, subIdToInfoMap, privilegedPackages);
210     }
211 
buildExpectedSnapshot( int activeSubId, Map<Integer, SubscriptionInfo> subIdToInfoMap, Map<ParcelUuid, Set<String>> privilegedPackages)212     private TelephonySubscriptionSnapshot buildExpectedSnapshot(
213             int activeSubId,
214             Map<Integer, SubscriptionInfo> subIdToInfoMap,
215             Map<ParcelUuid, Set<String>> privilegedPackages) {
216         return new TelephonySubscriptionSnapshot(activeSubId, subIdToInfoMap, privilegedPackages);
217     }
218 
verifyNoActiveSubscriptions()219     private void verifyNoActiveSubscriptions() {
220         verify(mCallback).onNewSnapshot(
221                 argThat(snapshot -> snapshot.getActiveSubscriptionGroups().isEmpty()));
222     }
223 
setupReadySubIds()224     private void setupReadySubIds() {
225         mTelephonySubscriptionTracker.setReadySubIdsBySlotId(
226                 Collections.singletonMap(TEST_SIM_SLOT_INDEX, TEST_SUBSCRIPTION_ID_1));
227     }
228 
setPrivilegedPackagesForMock(@onNull List<String> privilegedPackages)229     private void setPrivilegedPackagesForMock(@NonNull List<String> privilegedPackages) {
230         doReturn(privilegedPackages).when(mTelephonyManager).getPackagesWithCarrierPrivileges();
231     }
232 
233     @Test
testRegister()234     public void testRegister() throws Exception {
235         verify(mContext)
236                 .registerReceiver(
237                         eq(mTelephonySubscriptionTracker),
238                         any(IntentFilter.class),
239                         any(),
240                         eq(mHandler));
241         final IntentFilter filter = getIntentFilter();
242         assertEquals(1, filter.countActions());
243         assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED));
244 
245         verify(mSubscriptionManager)
246                 .addOnSubscriptionsChangedListener(any(HandlerExecutor.class), any());
247         assertNotNull(getOnSubscriptionsChangedListener());
248     }
249 
250     @Test
testUnregister()251     public void testUnregister() throws Exception {
252         mTelephonySubscriptionTracker.unregister();
253 
254         verify(mContext).unregisterReceiver(eq(mTelephonySubscriptionTracker));
255 
256         final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
257         verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(eq(listener));
258     }
259 
260     @Test
testOnSubscriptionsChangedFired_NoReadySubIds()261     public void testOnSubscriptionsChangedFired_NoReadySubIds() throws Exception {
262         final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
263         listener.onSubscriptionsChanged();
264         mTestLooper.dispatchAll();
265 
266         verifyNoActiveSubscriptions();
267     }
268 
269     @Test
testOnSubscriptionsChangedFired_onActiveSubIdsChanged()270     public void testOnSubscriptionsChangedFired_onActiveSubIdsChanged() throws Exception {
271         setupReadySubIds();
272         setPrivilegedPackagesForMock(Collections.emptyList());
273 
274         doReturn(TEST_SUBSCRIPTION_ID_2).when(mDeps).getActiveDataSubscriptionId();
275         final ActiveDataSubscriptionIdListener listener = getActiveDataSubscriptionIdListener();
276         listener.onActiveDataSubscriptionIdChanged(TEST_SUBSCRIPTION_ID_2);
277         mTestLooper.dispatchAll();
278 
279         ArgumentCaptor<TelephonySubscriptionSnapshot> snapshotCaptor =
280                 ArgumentCaptor.forClass(TelephonySubscriptionSnapshot.class);
281         verify(mCallback).onNewSnapshot(snapshotCaptor.capture());
282 
283         TelephonySubscriptionSnapshot snapshot = snapshotCaptor.getValue();
284         assertNotNull(snapshot);
285         assertEquals(TEST_SUBSCRIPTION_ID_2, snapshot.getActiveDataSubscriptionId());
286         assertEquals(TEST_PARCEL_UUID, snapshot.getActiveDataSubscriptionGroup());
287     }
288 
289     @Test
testOnSubscriptionsChangedFired_WithReadySubidsNoPrivilegedPackages()290     public void testOnSubscriptionsChangedFired_WithReadySubidsNoPrivilegedPackages()
291             throws Exception {
292         setupReadySubIds();
293         setPrivilegedPackagesForMock(Collections.emptyList());
294 
295         final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
296         listener.onSubscriptionsChanged();
297         mTestLooper.dispatchAll();
298 
299         final Map<ParcelUuid, Set<String>> privilegedPackages =
300                 Collections.singletonMap(TEST_PARCEL_UUID, new ArraySet<>());
301         verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(privilegedPackages)));
302     }
303 
304     @Test
testOnSubscriptionsChangedFired_WithReadySubidsAndPrivilegedPackages()305     public void testOnSubscriptionsChangedFired_WithReadySubidsAndPrivilegedPackages()
306             throws Exception {
307         setupReadySubIds();
308 
309         final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
310         listener.onSubscriptionsChanged();
311         mTestLooper.dispatchAll();
312 
313         verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
314     }
315 
316     @Test
testReceiveBroadcast_ConfigReadyWithSubscriptions()317     public void testReceiveBroadcast_ConfigReadyWithSubscriptions() throws Exception {
318         mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
319         mTestLooper.dispatchAll();
320 
321         verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
322     }
323 
324     @Test
testReceiveBroadcast_ConfigReadyNoSubscriptions()325     public void testReceiveBroadcast_ConfigReadyNoSubscriptions() throws Exception {
326         doReturn(new ArrayList<SubscriptionInfo>())
327                 .when(mSubscriptionManager)
328                 .getAllSubscriptionInfoList();
329 
330         mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
331         mTestLooper.dispatchAll();
332 
333         // Expect an empty snapshot
334         verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap(), emptyMap())));
335     }
336 
337     @Test
testReceiveBroadcast_SlotCleared()338     public void testReceiveBroadcast_SlotCleared() throws Exception {
339         setupReadySubIds();
340 
341         mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false));
342         mTestLooper.dispatchAll();
343 
344         verifyNoActiveSubscriptions();
345         assertTrue(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().isEmpty());
346     }
347 
348     @Test
testReceiveBroadcast_ConfigNotReady()349     public void testReceiveBroadcast_ConfigNotReady() throws Exception {
350         doReturn(false).when(mDeps).isConfigForIdentifiedCarrier(any());
351 
352         mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
353         mTestLooper.dispatchAll();
354 
355         // No interactions expected; config was not loaded
356         verifyNoMoreInteractions(mCallback);
357     }
358 
359     @Test
testSubscriptionsClearedAfterValidTriggersCallbacks()360     public void testSubscriptionsClearedAfterValidTriggersCallbacks() throws Exception {
361         mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
362         mTestLooper.dispatchAll();
363         verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
364         assertNotNull(
365                 mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
366 
367         doReturn(Collections.emptyList()).when(mSubscriptionManager).getAllSubscriptionInfoList();
368         mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
369         mTestLooper.dispatchAll();
370         verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap(), emptyMap())));
371     }
372 
373     @Test
testSlotClearedAfterValidTriggersCallbacks()374     public void testSlotClearedAfterValidTriggersCallbacks() throws Exception {
375         mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
376         mTestLooper.dispatchAll();
377         verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
378         assertNotNull(
379                 mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
380 
381         mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false));
382         mTestLooper.dispatchAll();
383         verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap())));
384         assertNull(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
385     }
386 
387     @Test
testChangingPrivilegedPackagesAfterValidTriggersCallbacks()388     public void testChangingPrivilegedPackagesAfterValidTriggersCallbacks() throws Exception {
389         setupReadySubIds();
390 
391         // Setup initial "valid" state
392         final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
393         listener.onSubscriptionsChanged();
394         mTestLooper.dispatchAll();
395 
396         verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
397 
398         // Simulate a loss of carrier privileges
399         setPrivilegedPackagesForMock(Collections.emptyList());
400         listener.onSubscriptionsChanged();
401         mTestLooper.dispatchAll();
402 
403         verify(mCallback)
404                 .onNewSnapshot(
405                         eq(buildExpectedSnapshot(singletonMap(TEST_PARCEL_UUID, emptySet()))));
406     }
407 
408     @Test
testTelephonySubscriptionSnapshotGetGroupForSubId()409     public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception {
410         final TelephonySubscriptionSnapshot snapshot =
411                 new TelephonySubscriptionSnapshot(
412                         TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap());
413 
414         assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1));
415         assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2));
416     }
417 
418     @Test
testTelephonySubscriptionSnapshotGetAllSubIdsInGroup()419     public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception {
420         final TelephonySubscriptionSnapshot snapshot =
421                 new TelephonySubscriptionSnapshot(
422                         TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap());
423 
424         assertEquals(
425                 new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)),
426                 snapshot.getAllSubIdsInGroup(TEST_PARCEL_UUID));
427     }
428 }
429