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.imsserviceentitlement;
18 
19 import static android.telephony.TelephonyManager.SIM_STATE_LOADED;
20 import static android.telephony.TelephonyManager.SIM_STATE_PIN_REQUIRED;
21 
22 import static com.android.imsserviceentitlement.ts43.Ts43Constants.EntitlementVersion.ENTITLEMENT_VERSION_EIGHT;
23 import static com.android.imsserviceentitlement.ts43.Ts43Constants.EntitlementVersion.ENTITLEMENT_VERSION_TWO;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import static org.mockito.Mockito.never;
28 import static org.mockito.Mockito.times;
29 import static org.mockito.Mockito.verify;
30 import static org.mockito.Mockito.when;
31 
32 import android.content.ComponentName;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.content.SharedPreferences;
36 import android.os.PersistableBundle;
37 import android.os.UserManager;
38 import android.provider.Settings;
39 import android.telephony.CarrierConfigManager;
40 import android.telephony.SubscriptionManager;
41 
42 import androidx.test.core.app.ApplicationProvider;
43 import androidx.test.runner.AndroidJUnit4;
44 
45 import com.android.imsserviceentitlement.entitlement.EntitlementConfiguration;
46 import com.android.imsserviceentitlement.job.JobManager;
47 import com.android.imsserviceentitlement.utils.Executors;
48 import com.android.imsserviceentitlement.utils.TelephonyUtils;
49 
50 import org.junit.After;
51 import org.junit.Before;
52 import org.junit.Rule;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.mockito.Mock;
56 import org.mockito.Spy;
57 import org.mockito.junit.MockitoJUnit;
58 import org.mockito.junit.MockitoRule;
59 
60 import java.lang.reflect.Field;
61 
62 @RunWith(AndroidJUnit4.class)
63 public class ImsEntitlementReceiverTest {
64     private static final int SUB_ID = 1;
65     private static final int LAST_SUB_ID = 2;
66     private static final String KEY_ENTITLEMENT_VERSION_INT =
67             "imsserviceentitlement.entitlement_version_int";
68     private static final String RAW_XML =
69             "<wap-provisioningdoc version=\"1.1\">\n"
70                     + "    <characteristic type=\"APPLICATION\">\n"
71                     + "        <parm name=\"AppID\" value=\"ap2004\"/>\n"
72                     + "        <parm name=\"EntitlementStatus\" value=\"1\"/>\n"
73                     + "    </characteristic>\n"
74                     + "</wap-provisioningdoc>\n";
75 
76     private static final String RAW_XML_VERSION_0_VALIDITY_0 =
77             "<wap-provisioningdoc version=\"1.1\">\n"
78                     + "    <characteristic type=\"VERS\">\n"
79                     + "        <parm name=\"version\" value=\"0\"/>\n"
80                     + "        <parm name=\"validity\" value=\"0\"/>\n"
81                     + "    </characteristic>\n"
82                     + "</wap-provisioningdoc>\n";
83 
84     private static final String RAW_XML_INVALID_VERS =
85             "<wap-provisioningdoc version=\"1.1\">\n"
86                     + "    <characteristic type=\"VERS\">\n"
87                     + "        <parm name=\"version\" value=\"-1\"/>\n"
88                     + "        <parm name=\"validity\" value=\"-1\"/>\n"
89                     + "    </characteristic>\n"
90                     + "</wap-provisioningdoc>\n";
91     private static final ComponentName POLLING_SERVICE_COMPONENT_NAME =
92             ComponentName.unflattenFromString(
93                     "com.android.imsserviceentitlement/.ImsEntitlementPollingService");
94 
95     @Rule public final MockitoRule rule = MockitoJUnit.rule();
96 
97     @Mock private TelephonyUtils mMockTelephonyUtils;
98     @Mock private UserManager mMockUserManager;
99     @Mock private CarrierConfigManager mCarrierConfigManager;
100     @Mock private JobManager mMockJobManager;
101 
102     @Spy private final Context mContext = ApplicationProvider.getApplicationContext();
103 
104     private ImsEntitlementReceiver mReceiver;
105     private PersistableBundle mCarrierConfig;
106     private boolean mIsBootUp;
107 
108     @Before
setUp()109     public void setUp() throws Exception {
110         mReceiver = new ImsEntitlementReceiver() {
111             @Override
112             protected Dependencies createDependency(Context context, int subId) {
113                 Dependencies dependencies = new Dependencies();
114                 dependencies.userManager = mMockUserManager;
115                 dependencies.telephonyUtils = mMockTelephonyUtils;
116                 dependencies.jobManager = mMockJobManager;
117                 return dependencies;
118             }
119 
120             @Override
121             protected boolean isBootUp(Context context, int slotId) {
122                 return mIsBootUp;
123             }
124         };
125         mIsBootUp = false;
126 
127         new EntitlementConfiguration(mContext, LAST_SUB_ID)
128                 .update(ENTITLEMENT_VERSION_TWO, RAW_XML);
129         new EntitlementConfiguration(mContext, SUB_ID).reset();
130 
131         when(mMockUserManager.isSystemUser()).thenReturn(true);
132         when(mMockTelephonyUtils.getSimApplicationState()).thenReturn(SIM_STATE_LOADED);
133 
134         setLastSubId(LAST_SUB_ID, 0);
135         setImsProvisioningBool(true);
136         useDirectExecutor();
137     }
138 
139     @After
tearDown()140     public void tearDown() {
141         mCarrierConfig = null;
142     }
143 
144     @Test
onReceive_simChanged_dataReset()145     public void onReceive_simChanged_dataReset() {
146         mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(SUB_ID, /* slotId= */ 0));
147 
148         assertThat(new EntitlementConfiguration(mContext, LAST_SUB_ID).getRawXml()).isEqualTo(null);
149         verify(mMockJobManager, times(1)).queryEntitlementStatusOnceNetworkReady();
150     }
151 
152     @Test
onReceive_simChanged_simPinLockedThenLoaded()153     public void onReceive_simChanged_simPinLockedThenLoaded() {
154         // SIM PIN locked
155         when(mMockTelephonyUtils.getSimApplicationState()).thenReturn(SIM_STATE_PIN_REQUIRED);
156 
157         mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(SUB_ID, /* slotId= */ 0));
158 
159         // no-op
160         assertThat(new EntitlementConfiguration(mContext, LAST_SUB_ID).getRawXml())
161                 .isEqualTo(RAW_XML);
162         verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
163 
164         // SIM LOADED
165         when(mMockTelephonyUtils.getSimApplicationState()).thenReturn(SIM_STATE_LOADED);
166 
167         mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(SUB_ID, /* slotId= */ 0));
168 
169         // configuration reset and entitlement query scheduled.
170         assertThat(new EntitlementConfiguration(mContext, LAST_SUB_ID).getRawXml()).isEqualTo(null);
171         verify(mMockJobManager, times(1)).queryEntitlementStatusOnceNetworkReady();
172     }
173 
174     @Test
onReceive_theSameSim_dataNotReset()175     public void onReceive_theSameSim_dataNotReset() {
176         mReceiver.onReceive(
177                 mContext, getCarrierConfigChangedIntent(LAST_SUB_ID, /* slotId= */ 0));
178 
179         assertThat(new EntitlementConfiguration(mContext, LAST_SUB_ID).getRawXml())
180                 .isEqualTo(RAW_XML);
181         verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
182     }
183 
184     @Test
onReceive_differentSlot_dataNotReset()185     public void onReceive_differentSlot_dataNotReset() {
186         setLastSubId(LAST_SUB_ID, 1);
187 
188         mReceiver.onReceive(
189                 mContext, getCarrierConfigChangedIntent(LAST_SUB_ID, /* slotId= */ 1));
190 
191         assertThat(new EntitlementConfiguration(mContext, LAST_SUB_ID).getRawXml())
192                 .isEqualTo(RAW_XML);
193         verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
194     }
195 
196     @Test
onReceive_simChangedAndDifferentSlotId_dataReset()197     public void onReceive_simChangedAndDifferentSlotId_dataReset() {
198         setLastSubId(LAST_SUB_ID, 1);
199 
200         mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(SUB_ID, /* slotId= */ 1));
201 
202         assertThat(new EntitlementConfiguration(mContext, LAST_SUB_ID).getRawXml()).isEqualTo(null);
203         verify(mMockJobManager).queryEntitlementStatusOnceNetworkReady();
204     }
205 
206     @Test
onReceive_isSystemUser_jobScheduled()207     public void onReceive_isSystemUser_jobScheduled() {
208         mReceiver.onReceive(
209                 mContext, getCarrierConfigChangedIntent(SUB_ID, /* slotId= */ 0));
210 
211         verify(mMockJobManager).queryEntitlementStatusOnceNetworkReady();
212     }
213 
214     @Test
onReceive_notSystemUser_noJobScheduled()215     public void onReceive_notSystemUser_noJobScheduled() {
216         ImsEntitlementReceiver receiver = new ImsEntitlementReceiver();
217 
218         receiver.onReceive(
219                 mContext, getCarrierConfigChangedIntent(SUB_ID, /* slotId= */ 0));
220 
221         verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
222     }
223 
224     @Test
onReceive_deviceBootUp_jobScheduled()225     public void onReceive_deviceBootUp_jobScheduled() {
226         new EntitlementConfiguration(mContext, LAST_SUB_ID)
227                 .update(ENTITLEMENT_VERSION_TWO, RAW_XML_VERSION_0_VALIDITY_0);
228         mIsBootUp = true;
229 
230         mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(LAST_SUB_ID, /* slotId= */ 0));
231 
232         verify(mMockJobManager).queryEntitlementStatusOnceNetworkReady();
233     }
234 
235     @Test
onReceive_bootCompleteInvalidVers_noJobScheduled()236     public void onReceive_bootCompleteInvalidVers_noJobScheduled() {
237         new EntitlementConfiguration(mContext, LAST_SUB_ID)
238                 .update(ENTITLEMENT_VERSION_TWO, RAW_XML_INVALID_VERS);
239         mIsBootUp = true;
240 
241         mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(LAST_SUB_ID, /* slotId= */ 0));
242 
243         verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
244     }
245 
246     @Test
247     public void
onReceiveAndEntitlementUpdatedFromZeroToTwo_bootCompleteInvalidVers_noJobScheduled()248             onReceiveAndEntitlementUpdatedFromZeroToTwo_bootCompleteInvalidVers_noJobScheduled() {
249         new EntitlementConfiguration(mContext, LAST_SUB_ID).update(0, RAW_XML_INVALID_VERS);
250         setEntitlementVersion(ENTITLEMENT_VERSION_TWO);
251         mIsBootUp = true;
252 
253         mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(LAST_SUB_ID, /* slotId= */ 0));
254 
255         verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
256     }
257 
258     @Test
259     public void
onReceiveAndEntitlementUpdatedFromZeroToEight_bootCompleteInvalidVers_JobScheduled()260             onReceiveAndEntitlementUpdatedFromZeroToEight_bootCompleteInvalidVers_JobScheduled() {
261         new EntitlementConfiguration(mContext, LAST_SUB_ID).update(0, RAW_XML_INVALID_VERS);
262         setEntitlementVersion(ENTITLEMENT_VERSION_EIGHT);
263         mIsBootUp = true;
264 
265         mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(LAST_SUB_ID, /* slotId= */ 0));
266 
267         verify(mMockJobManager).queryEntitlementStatusOnceNetworkReady();
268     }
269 
270     @Test
onReceive_unsupportedEntitlementVersion_noJobScheduled()271     public void onReceive_unsupportedEntitlementVersion_noJobScheduled() {
272         setEntitlementVersion(1);
273 
274         mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(LAST_SUB_ID, 0));
275 
276         verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
277     }
278 
279     @Test
onReceive_invalidSubId_noJobScheduled()280     public void onReceive_invalidSubId_noJobScheduled() {
281         mReceiver.onReceive(mContext,
282                 getCarrierConfigChangedIntent(SubscriptionManager.INVALID_SUBSCRIPTION_ID, 0));
283 
284         verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
285     }
286 
287     @Test
isBootUp_compareWithLastBootCount_returnResult()288     public void isBootUp_compareWithLastBootCount_returnResult() {
289         int currentBootCount =
290                 Settings.Global.getInt(
291                         mContext.getContentResolver(), Settings.Global.BOOT_COUNT, /* def= */ -1);
292         setLastBootCount(/* slotId= */ 0, /* count=*/ currentBootCount);
293         setLastBootCount(/* slotId= */ 1, /* count=*/ currentBootCount - 1);
294         ImsEntitlementReceiver receiver = new ImsEntitlementReceiver();
295 
296         assertThat(receiver.isBootUp(mContext, 0)).isFalse();
297         assertThat(receiver.isBootUp(mContext, 1)).isTrue();
298     }
299 
getCarrierConfigChangedIntent(int subId, int slotId)300     private Intent getCarrierConfigChangedIntent(int subId, int slotId) {
301         Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
302         intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
303         intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, slotId);
304         return intent;
305     }
306 
setImsProvisioningBool(boolean provisioning)307     private void setImsProvisioningBool(boolean provisioning) {
308         initializeCarrierConfig();
309         mCarrierConfig.putBoolean(
310                 CarrierConfigManager.ImsServiceEntitlement.KEY_IMS_PROVISIONING_BOOL, provisioning);
311     }
312 
setEntitlementVersion(int entitlementVersion)313     private void setEntitlementVersion(int entitlementVersion) {
314         initializeCarrierConfig();
315         mCarrierConfig.putInt(KEY_ENTITLEMENT_VERSION_INT, entitlementVersion);
316     }
317 
initializeCarrierConfig()318     private void initializeCarrierConfig() {
319         if (mCarrierConfig == null) {
320             mCarrierConfig = new PersistableBundle();
321             when(mCarrierConfigManager.getConfigForSubId(SUB_ID)).thenReturn(mCarrierConfig);
322             when(mCarrierConfigManager.getConfigForSubId(LAST_SUB_ID)).thenReturn(mCarrierConfig);
323             when(mContext.getSystemService(CarrierConfigManager.class))
324                     .thenReturn(mCarrierConfigManager);
325         }
326     }
327 
setLastSubId(int subId, int slotId)328     private void setLastSubId(int subId, int slotId) {
329         SharedPreferences preferences =
330                 mContext.getSharedPreferences("PREFERENCE_ACTIVATION_INFO", Context.MODE_PRIVATE);
331         preferences.edit().putInt("last_sub_id_" + slotId, subId).apply();
332     }
333 
setLastBootCount(int slotId, int count)334     private void setLastBootCount(int slotId, int count) {
335         SharedPreferences preferences =
336                 mContext.getSharedPreferences("PREFERENCE_ACTIVATION_INFO", Context.MODE_PRIVATE);
337         preferences.edit().putInt("last_boot_count_" + slotId, count).apply();
338     }
339 
useDirectExecutor()340     private void useDirectExecutor() throws Exception {
341         Field field = Executors.class.getDeclaredField("sUseDirectExecutorForTest");
342         field.setAccessible(true);
343         field.set(null, true);
344     }
345 }
346