1 /*
2  * Copyright (C) 2016 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.internal.telephony.gsm;
18 
19 import static android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED;
20 import static android.telephony.SmsManager.SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE;
21 
22 import static com.android.internal.telephony.SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
23 import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
24 
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertTrue;
27 import static org.mockito.Matchers.any;
28 import static org.mockito.Matchers.anyInt;
29 import static org.mockito.Matchers.anyString;
30 import static org.mockito.Mockito.doAnswer;
31 import static org.mockito.Mockito.doReturn;
32 import static org.mockito.Mockito.times;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.when;
35 
36 import android.app.Activity;
37 import android.app.ActivityManager;
38 import android.app.PendingIntent;
39 import android.content.BroadcastReceiver;
40 import android.content.ComponentName;
41 import android.content.Context;
42 import android.content.Intent;
43 import android.content.IntentFilter;
44 import android.content.pm.PackageManager;
45 import android.content.pm.ServiceInfo;
46 import android.location.Country;
47 import android.location.CountryDetector;
48 import android.os.HandlerThread;
49 import android.os.Message;
50 import android.os.RemoteException;
51 import android.os.SystemProperties;
52 import android.provider.Settings;
53 import android.service.carrier.CarrierMessagingService;
54 import android.service.carrier.ICarrierMessagingCallback;
55 import android.service.carrier.ICarrierMessagingService;
56 import android.telephony.SmsManager;
57 import android.testing.AndroidTestingRunner;
58 import android.testing.TestableLooper;
59 import android.util.Singleton;
60 
61 import androidx.test.filters.FlakyTest;
62 import androidx.test.filters.MediumTest;
63 import androidx.test.filters.SmallTest;
64 
65 import com.android.internal.telephony.ContextFixture;
66 import com.android.internal.telephony.ISub;
67 import com.android.internal.telephony.SMSDispatcher;
68 import com.android.internal.telephony.SmsDispatchersController;
69 import com.android.internal.telephony.TelephonyTest;
70 import com.android.internal.telephony.TelephonyTestUtils;
71 import com.android.internal.telephony.TestApplication;
72 
73 import org.junit.After;
74 import org.junit.Before;
75 import org.junit.Ignore;
76 import org.junit.Test;
77 import org.junit.runner.RunWith;
78 import org.mockito.ArgumentCaptor;
79 import org.mockito.Mock;
80 import org.mockito.invocation.InvocationOnMock;
81 import org.mockito.stubbing.Answer;
82 
83 import java.util.ArrayList;
84 import java.util.HashMap;
85 import java.util.List;
86 
87 @RunWith(AndroidTestingRunner.class)
88 @TestableLooper.RunWithLooper
89 public class GsmSmsDispatcherTest extends TelephonyTest {
90 
91     private static final long TIMEOUT_MS = 500;
92     private static final String CARRIER_APP_PACKAGE_NAME = "com.android.carrier";
93 
94     @Mock
95     private android.telephony.SmsMessage mSmsMessage;
96     @Mock
97     private SmsMessage mGsmSmsMessage;
98     @Mock
99     private SmsDispatchersController mSmsDispatchersController;
100     @Mock
101     private GsmInboundSmsHandler mGsmInboundSmsHandler;
102     @Mock
103     private CountryDetector mCountryDetector;
104     @Mock
105     private SMSDispatcher.SmsTracker mSmsTracker;
106     @Mock
107     private ISub.Stub mISubStub;
108     @Mock
109     private ICarrierMessagingService.Stub mICarrierAppMessagingService;
110 
111     private Object mLock = new Object();
112     private boolean mReceivedTestIntent;
113     private static final String TEST_INTENT = "com.android.internal.telephony.TEST_INTENT";
114     private BroadcastReceiver mTestReceiver = new BroadcastReceiver() {
115         @Override
116         public void onReceive(Context context, Intent intent) {
117             logd("onReceive");
118             synchronized (mLock) {
119                 mReceivedTestIntent = true;
120                 mLock.notifyAll();
121             }
122         }
123     };
124 
125     private GsmSMSDispatcher mGsmSmsDispatcher;
126     private GsmSmsDispatcherTestHandler mGsmSmsDispatcherTestHandler;
127 
128     private class GsmSmsDispatcherTestHandler extends HandlerThread {
129 
GsmSmsDispatcherTestHandler(String name)130         private GsmSmsDispatcherTestHandler(String name) {
131             super(name);
132         }
133 
134         @Override
onLooperPrepared()135         public void onLooperPrepared() {
136             mGsmSmsDispatcher = new GsmSMSDispatcher(mPhone, mSmsDispatchersController,
137                     mGsmInboundSmsHandler);
138             setReady(true);
139         }
140     }
141 
142     @Before
setUp()143     public void setUp() throws Exception {
144 
145         super.setUp(getClass().getSimpleName());
146 
147         // Note that this replaces only cached services in ServiceManager. If a service is not found
148         // in the cache, a real instance is used.
149         mServiceManagerMockedServices.put("isub", mISubStub);
150 
151         doReturn(mSmsUsageMonitor).when(mSmsDispatchersController).getUsageMonitor();
152         mGsmSmsDispatcherTestHandler = new GsmSmsDispatcherTestHandler(getClass().getSimpleName());
153         mGsmSmsDispatcherTestHandler.start();
154         waitUntilReady();
155         mGsmSmsDispatcher = new GsmSMSDispatcher(mPhone, mSmsDispatchersController,
156                 mGsmInboundSmsHandler);
157         processAllMessages();
158     }
159 
160     @After
tearDown()161     public void tearDown() throws Exception {
162         mGsmSmsDispatcher = null;
163         mGsmSmsDispatcherTestHandler.quit();
164         mGsmSmsDispatcherTestHandler.join();
165         super.tearDown();
166     }
167 
168     @Test @SmallTest
testSmsStatus()169     public void testSmsStatus() {
170         mSimulatedCommands.notifySmsStatus(new byte[]{(byte)0xFF, (byte)0xFF, (byte)0xFF});
171         processAllMessages();
172         verify(mSimulatedCommandsVerifier).acknowledgeLastIncomingGsmSms(true, 0, null);
173     }
174 
175     @Test @MediumTest
testSendSmsToRegularNumber_doesNotNotifyblockedNumberProvider()176     public void testSendSmsToRegularNumber_doesNotNotifyblockedNumberProvider() throws Exception {
177         setupMockPackagePermissionChecks();
178 
179         mContextFixture.setSystemService(Context.COUNTRY_DETECTOR, mCountryDetector);
180         when(mCountryDetector.detectCountry())
181                 .thenReturn(new Country("US", Country.COUNTRY_SOURCE_SIM));
182 
183         mGsmSmsDispatcher.sendText("6501002000", "121" /*scAddr*/, "test sms",
184                 null, null, null, null, false, -1, false, -1, false, 0L);
185 
186         verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), any(Message.class));
187         // Blocked number provider is notified about the emergency contact asynchronously.
188         TelephonyTestUtils.waitForMs(50);
189         assertEquals(0, mFakeBlockedNumberContentProvider.mNumEmergencyContactNotifications);
190     }
191 
192     @FlakyTest
193     @Ignore
194     @Test @MediumTest
testSendSmsToEmergencyNumber_notifiesBlockedNumberProvider()195     public void testSendSmsToEmergencyNumber_notifiesBlockedNumberProvider() throws Exception {
196         setupMockPackagePermissionChecks();
197 
198         mContextFixture.setSystemService(Context.COUNTRY_DETECTOR, mCountryDetector);
199         when(mCountryDetector.detectCountry())
200                 .thenReturn(new Country("US", Country.COUNTRY_SOURCE_SIM));
201 
202         mGsmSmsDispatcher.sendText(
203                 getEmergencyNumberFromSystemPropertiesOrDefault(), "121" /*scAddr*/, "test sms",
204                 null, null, null, null, false, -1, false, -1, false, 0L);
205 
206         verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), any(Message.class));
207         // Blocked number provider is notified about the emergency contact asynchronously.
208         TelephonyTestUtils.waitForMs(50);
209         assertEquals(1, mFakeBlockedNumberContentProvider.mNumEmergencyContactNotifications);
210     }
211 
212     @Test @SmallTest
testSmsMessageValidityPeriod()213     public void testSmsMessageValidityPeriod() throws Exception {
214         int vp;
215         vp = SmsMessage.getRelativeValidityPeriod(-5);
216         assertEquals(-1, vp);
217 
218         vp = SmsMessage.getRelativeValidityPeriod(100);
219         assertEquals(100 / 5 - 1, vp);
220     }
221 
getEmergencyNumberFromSystemPropertiesOrDefault()222     private String getEmergencyNumberFromSystemPropertiesOrDefault() {
223         String systemEmergencyNumbers = SystemProperties.get("ril.ecclist");
224         if (systemEmergencyNumbers == null) {
225             return "911";
226         } else {
227             return systemEmergencyNumbers.split(",")[0];
228         }
229     }
230 
registerTestIntentReceiver()231     private void registerTestIntentReceiver() throws Exception {
232         // unmock ActivityManager to be able to register receiver, create real PendingIntent and
233         // receive TEST_INTENT
234         restoreInstance(Singleton.class, "mInstance", mIActivityManagerSingleton);
235         restoreInstance(ActivityManager.class, "IActivityManagerSingleton", null);
236         Context realContext = TestApplication.getAppContext();
237         realContext.registerReceiver(mTestReceiver, new IntentFilter(TEST_INTENT));
238     }
239 
240     @Test
241     @SmallTest
242     @FlakyTest
243     @Ignore
testSendTextWithInvalidDestAddr()244     public void testSendTextWithInvalidDestAddr() throws Exception {
245         registerTestIntentReceiver();
246         PendingIntent pendingIntent = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0,
247                 new Intent(TEST_INTENT), 0);
248         // send invalid dest address: +
249         mReceivedTestIntent = false;
250         mGsmSmsDispatcher.sendText("+", "222" /*scAddr*/, TAG,
251                 pendingIntent, null, null, null, false, -1, false, -1, false, 0L);
252         waitForMs(500);
253         verify(mSimulatedCommandsVerifier, times(0)).sendSMS(anyString(), anyString(),
254                 any(Message.class));
255         synchronized (mLock) {
256             assertEquals(true, mReceivedTestIntent);
257             assertEquals(SmsManager.RESULT_ERROR_NULL_PDU, mTestReceiver.getResultCode());
258         }
259     }
260 
261     @Test
testSendRawPduWithEventStopSending()262     public void testSendRawPduWithEventStopSending() throws Exception {
263         setupMockPackagePermissionChecks();
264         mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
265 
266         // return a fake value to pass getData()
267         HashMap data = new HashMap<String, String>();
268         data.put("pdu", new byte[1]);
269         when(mSmsTracker.getData()).thenReturn(data);
270 
271         // Set values to return to simulate EVENT_STOP_SENDING
272         when(mSmsUsageMonitor.checkDestination(any(), any()))
273                 .thenReturn(SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE);
274         when(mSmsUsageMonitor.getPremiumSmsPermission(any()))
275                 .thenReturn(PREMIUM_SMS_PERMISSION_NEVER_ALLOW);
276         when(mSmsTracker.getAppPackageName()).thenReturn("");
277 
278         // Settings.Global.DEVICE_PROVISIONED to 1
279         Settings.Global.putInt(mContext.getContentResolver(),
280                 Settings.Global.DEVICE_PROVISIONED, 1);
281 
282         mGsmSmsDispatcher.sendRawPdu(new SMSDispatcher.SmsTracker[] {mSmsTracker});
283         //waitForHandlerAction(mGsmSmsDispatcher, TIMEOUT_MS);
284         processAllMessages();
285 
286         verify(mSmsUsageMonitor, times(1)).checkDestination(any(), any());
287         verify(mSmsUsageMonitor, times(1)).getPremiumSmsPermission(any());
288         ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor
289                 .forClass(Integer.class);
290         verify(mSmsTracker, times(1)).onFailed(any(), argumentCaptor.capture(), anyInt());
291         assertEquals(RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, (int) argumentCaptor.getValue());
292     }
293 
294     @Test @SmallTest
295     @FlakyTest
296     @Ignore
testSendMultipartTextWithInvalidText()297     public void testSendMultipartTextWithInvalidText() throws Exception {
298         registerTestIntentReceiver();
299 
300         // initiate parameters for an invalid text MO SMS (the 2nd segmeant has 161 characters)
301         ArrayList<String> parts = new ArrayList<>();
302         parts.add("valid segment1");
303         parts.add("too long segment2 12345678912345678912345678912345678912345678912345678912345678"
304                 + "91234567891234567891234567891234567891234567891234567891234567891234567891234567"
305                 + "8");
306 
307         ArrayList<PendingIntent> sentIntents = new ArrayList<>();
308         PendingIntent sentIntent = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0,
309                 new Intent(TEST_INTENT), PendingIntent.FLAG_IMMUTABLE);
310         sentIntents.add(sentIntent);
311         sentIntents.add(sentIntent);
312 
313         // send SMS and check sentIntent
314         mReceivedTestIntent = false;
315         mGsmSmsDispatcher.sendMultipartText("+123" /*destAddr*/, "222" /*scAddr*/, parts,
316                 sentIntents, null, null, null, false, -1, false, -1, 0L);
317 
318         waitForMs(500);
319         synchronized (mLock) {
320             assertEquals(true, mReceivedTestIntent);
321             assertEquals(SmsManager.RESULT_ERROR_GENERIC_FAILURE, mTestReceiver.getResultCode());
322         }
323     }
324 
mockCarrierApp()325     private void mockCarrierApp()
326             throws RemoteException {
327         mContextFixture.addService(
328                 CarrierMessagingService.SERVICE_INTERFACE,
329                 new ComponentName(CARRIER_APP_PACKAGE_NAME, "CarrierAppFilterClass"),
330                 CARRIER_APP_PACKAGE_NAME,
331                 mICarrierAppMessagingService,
332                 new ServiceInfo());
333         when(mICarrierAppMessagingService.asBinder()).thenReturn(mICarrierAppMessagingService);
334         mockUiccWithCarrierApp();
335     }
336 
mockUiccWithCarrierApp()337     private void mockUiccWithCarrierApp() {
338         when(mUiccController.getUiccCard(mPhone.getPhoneId())).thenReturn(mUiccCard);
339         List<String> carrierPackages = new ArrayList<>();
340         carrierPackages.add(CARRIER_APP_PACKAGE_NAME);
341         when(mUiccCard.getCarrierPackageNamesForIntent(
342                 any(PackageManager.class), any(Intent.class))).thenReturn(carrierPackages);
343     }
344 
mockCarrierAppStubResults(final int result, ICarrierMessagingService.Stub stub, boolean callOnFilterComplete)345     private void mockCarrierAppStubResults(final int result, ICarrierMessagingService.Stub stub,
346             boolean callOnFilterComplete)
347             throws RemoteException {
348         when(stub.queryLocalInterface(anyString())).thenReturn(stub);
349         when(stub.asBinder()).thenReturn(stub);
350         // for single part
351         doAnswer(new Answer<Void>() {
352             @Override
353             public Void answer(InvocationOnMock invocation) throws Throwable {
354                 Object[] args = invocation.getArguments();
355                 ICarrierMessagingCallback callback = (ICarrierMessagingCallback) args[4];
356                 if (callOnFilterComplete) {
357                     callback.onSendSmsComplete(result, 0);
358                 }
359                 return null;
360             }
361         }).when(stub).sendTextSms(
362                 anyString(), anyInt(), anyString(), anyInt(),
363                 any(ICarrierMessagingCallback.class));
364 
365         // for multi part
366         doAnswer(new Answer<Void>() {
367             @Override
368             public Void answer(InvocationOnMock invocation) throws Throwable {
369                 Object[] args = invocation.getArguments();
370                 ICarrierMessagingCallback callback = (ICarrierMessagingCallback) args[4];
371                 if (callOnFilterComplete) {
372                     callback.onSendMultipartSmsComplete(result, null);
373                 }
374                 return null;
375             }
376         }).when(stub).sendMultipartTextSms(
377                 any(), anyInt(), anyString(), anyInt(),
378                 any(ICarrierMessagingCallback.class));
379     }
380 
381     @Test
382     @SmallTest
testSendSmsByCarrierApp()383     public void testSendSmsByCarrierApp() throws Exception {
384         mockCarrierApp();
385         mockCarrierAppStubResults(CarrierMessagingService.SEND_STATUS_OK,
386                 mICarrierAppMessagingService, true);
387         registerTestIntentReceiver();
388 
389         PendingIntent pendingIntent = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0,
390                 new Intent(TEST_INTENT), PendingIntent.FLAG_MUTABLE);
391         mReceivedTestIntent = false;
392 
393         mGsmSmsDispatcher.sendText("6501002000", "121" /*scAddr*/, "test sms",
394                 pendingIntent, null, null, null, false, -1, false, -1, false, 0L);
395         processAllMessages();
396         synchronized (mLock) {
397             if (!mReceivedTestIntent) {
398                 // long wait since sometimes broadcasts can take a long time if the system is loaded
399                 mLock.wait(60000);
400             }
401             assertEquals(true, mReceivedTestIntent);
402             int resultCode = mTestReceiver.getResultCode();
403             assertTrue("Unexpected result code: " + resultCode,
404                     resultCode == SmsManager.RESULT_ERROR_NONE || resultCode == Activity.RESULT_OK);
405             verify(mSimulatedCommandsVerifier, times(0)).sendSMS(anyString(), anyString(),
406                     any(Message.class));
407         }
408     }
409 
410     @Test
411     @SmallTest
testSendSmsByCarrierAppNoResponse()412     public void testSendSmsByCarrierAppNoResponse() throws Exception {
413         mockCarrierApp();
414         // do not mock result, instead reduce the timeout for test
415         mGsmSmsDispatcher.mCarrierMessagingTimeout = 100;
416 
417         mGsmSmsDispatcher.sendText("6501002000", "121" /*scAddr*/, "test sms",
418                 null, null, null, null, false, -1, false, -1, false, 0L);
419         // wait for timeout
420         waitForMs(150);
421         verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), any(Message.class));
422     }
423 
424     @Test
425     @SmallTest
testSendSmsByCarrierAppBindingFailed()426     public void testSendSmsByCarrierAppBindingFailed() throws Exception {
427         mContextFixture.mockBindingFailureForPackage(CARRIER_APP_PACKAGE_NAME);
428         // mock presence of carrier app, but do not create a mock service to make binding fail
429         mockUiccWithCarrierApp();
430 
431         mGsmSmsDispatcher.sendText("6501002000", "121" /*scAddr*/, "test sms",
432                 null, null, null, null, false, -1, false, -1, false, 0L);
433         processAllMessages();
434         verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), any(Message.class));
435     }
436 
sendMultipartTextSms(boolean withSentIntents)437     private void sendMultipartTextSms(boolean withSentIntents) {
438         // initiate parameters for a multipart sms
439         ArrayList<String> parts = new ArrayList<>();
440         parts.add("segment1");
441         parts.add("segment2");
442 
443         ArrayList<PendingIntent> sentIntents = new ArrayList<>();
444         PendingIntent sentIntent1 = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0,
445                 new Intent(TEST_INTENT), PendingIntent.FLAG_MUTABLE);
446         PendingIntent sentIntent2 = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0,
447                 new Intent(TEST_INTENT), PendingIntent.FLAG_MUTABLE);
448         sentIntents.add(sentIntent1);
449         sentIntents.add(sentIntent2);
450 
451         mGsmSmsDispatcher.sendMultipartText("6501002000" /*destAddr*/, "222" /*scAddr*/, parts,
452                 withSentIntents ? sentIntents : null, null, null, null, false, -1, false, -1, 0L);
453     }
454 
455     @Test
456     @SmallTest
testSendMultipartSmsByCarrierApp()457     public void testSendMultipartSmsByCarrierApp() throws Exception {
458         mockCarrierApp();
459         mockCarrierAppStubResults(CarrierMessagingService.SEND_STATUS_OK,
460                 mICarrierAppMessagingService, true);
461         registerTestIntentReceiver();
462 
463         // send SMS and check sentIntent
464         mReceivedTestIntent = false;
465         sendMultipartTextSms(true);
466         processAllMessages();
467         synchronized (mLock) {
468             if (!mReceivedTestIntent) {
469                 // long wait since sometimes broadcasts can take a long time if the system is loaded
470                 mLock.wait(60000);
471             }
472             assertEquals(true, mReceivedTestIntent);
473             int resultCode = mTestReceiver.getResultCode();
474             assertTrue("Unexpected result code: " + resultCode,
475                     resultCode == SmsManager.RESULT_ERROR_NONE || resultCode == Activity.RESULT_OK);
476             verify(mSimulatedCommandsVerifier, times(0)).sendSMS(anyString(), anyString(),
477                     any(Message.class));
478         }
479     }
480 
481     @Test
482     @SmallTest
testSendMultipartSmsByCarrierAppNoResponse()483     public void testSendMultipartSmsByCarrierAppNoResponse() throws Exception {
484         mockCarrierApp();
485         // do not mock result, instead reduce the timeout for test
486         mGsmSmsDispatcher.mCarrierMessagingTimeout = 100;
487 
488         sendMultipartTextSms(false);
489 
490         // wait for timeout
491         waitForMs(150);
492         verify(mSimulatedCommandsVerifier).sendSMSExpectMore(anyString(), anyString(),
493                 any(Message.class));
494         verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(),
495                 any(Message.class));
496     }
497 
498     @Test
499     @SmallTest
testSendMultipartSmsByCarrierAppBindingFailed()500     public void testSendMultipartSmsByCarrierAppBindingFailed() throws Exception {
501         mContextFixture.mockBindingFailureForPackage(CARRIER_APP_PACKAGE_NAME);
502         // mock presence of carrier app, but do not create a mock service to make binding fail
503         mockUiccWithCarrierApp();
504 
505         sendMultipartTextSms(false);
506 
507         processAllMessages();
508         verify(mSimulatedCommandsVerifier).sendSMSExpectMore(anyString(), anyString(),
509                 any(Message.class));
510         verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(),
511                 any(Message.class));
512     }
513 }
514