• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.ondevicepersonalization.services;
18 
19 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ON_DEVICE_PERSONALIZATION_ERROR;
20 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__ODP;
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertNotEquals;
25 import static org.junit.Assert.assertThrows;
26 import static org.junit.Assert.assertTrue;
27 import static org.mockito.ArgumentMatchers.any;
28 import static org.mockito.ArgumentMatchers.anyString;
29 import static org.mockito.ArgumentMatchers.eq;
30 import static org.mockito.ArgumentMatchers.isA;
31 import static org.mockito.Mockito.spy;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.when;
34 
35 import android.adservices.ondevicepersonalization.Constants;
36 import android.adservices.ondevicepersonalization.aidl.IOnDevicePersonalizationConfigServiceCallback;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.pm.PackageManager;
40 import android.os.Build;
41 import android.os.IBinder;
42 
43 import androidx.test.core.app.ApplicationProvider;
44 import androidx.test.filters.SdkSuppress;
45 import androidx.test.rule.ServiceTestRule;
46 
47 import com.android.modules.utils.testing.ExtendedMockitoRule;
48 import com.android.modules.utils.testing.ExtendedMockitoRule.MockStatic;
49 import com.android.ondevicepersonalization.services.data.user.RawUserData;
50 import com.android.ondevicepersonalization.services.data.user.UserDataCollector;
51 import com.android.ondevicepersonalization.services.data.user.UserPrivacyStatus;
52 import com.android.ondevicepersonalization.services.statsd.errorlogging.ClientErrorLogger;
53 
54 import org.junit.After;
55 import org.junit.Before;
56 import org.junit.Rule;
57 import org.junit.Test;
58 import org.junit.runner.RunWith;
59 import org.junit.runners.JUnit4;
60 import org.mockito.Mock;
61 import org.mockito.quality.Strictness;
62 
63 import java.util.TimeZone;
64 import java.util.concurrent.CountDownLatch;
65 import java.util.concurrent.TimeUnit;
66 import java.util.concurrent.TimeoutException;
67 
68 @RunWith(JUnit4.class)
69 @MockStatic(ClientErrorLogger.class)
70 public class OnDevicePersonalizationConfigServiceTest {
71     @Rule
72     public final ExtendedMockitoRule extendedMockitoRule =
73             new ExtendedMockitoRule.Builder(this).setStrictness(Strictness.LENIENT).build();
74 
75     @Rule
76     public final ServiceTestRule serviceRule = new ServiceTestRule();
77     private Context mContext = spy(ApplicationProvider.getApplicationContext());
78     private OnDevicePersonalizationConfigServiceDelegate mBinder;
79     private UserPrivacyStatus mUserPrivacyStatus;
80     private RawUserData mUserData;
81     private UserDataCollector mUserDataCollector;
82     @Mock
83     private ClientErrorLogger mMockClientErrorLogger;
84 
85     @Before
86     public void setup() throws Exception {
87 
88         PhFlagsTestUtil.setUpDeviceConfigPermissions();
89         PhFlagsTestUtil.disableGlobalKillSwitch();
90         PhFlagsTestUtil.disablePersonalizationStatusOverride();
91         when(mContext.checkCallingPermission(anyString()))
92                         .thenReturn(PackageManager.PERMISSION_GRANTED);
93         mBinder = new OnDevicePersonalizationConfigServiceDelegate(mContext);
94         mUserPrivacyStatus = UserPrivacyStatus.getInstanceForTest();
95         mUserPrivacyStatus.setPersonalizationStatusEnabled(false);
96         mUserData = RawUserData.getInstance();
97         TimeZone pstTime = TimeZone.getTimeZone("GMT-08:00");
98         TimeZone.setDefault(pstTime);
99         mUserDataCollector = UserDataCollector.getInstanceForTest(mContext);
100         when(ClientErrorLogger.getInstance()).thenReturn(mMockClientErrorLogger);
101     }
102 
103     @Test
104     public void testThrowIfGlobalKillSwitchEnabled() throws Exception {
105         PhFlagsTestUtil.enableGlobalKillSwitch();
106         try {
107             assertThrows(
108                     IllegalStateException.class,
109                     () ->
110                             mBinder.setPersonalizationStatus(true, null)
111             );
112         } finally {
113             PhFlagsTestUtil.disableGlobalKillSwitch();
114         }
115     }
116 
117     @Test
118     public void testSetPersonalizationStatusNoCallingPermission() throws Exception {
119         when(mContext.checkCallingPermission(anyString()))
120                         .thenReturn(PackageManager.PERMISSION_DENIED);
121         assertThrows(SecurityException.class, () -> {
122             mBinder.setPersonalizationStatus(true, null);
123         });
124     }
125 
126     @Test
127     public void testSetPersonalizationStatusChanged() throws Exception {
128         assertFalse(mUserPrivacyStatus.isPersonalizationStatusEnabled());
129         populateUserData();
130         assertNotEquals(0, mUserData.utcOffset);
131         assertTrue(mUserDataCollector.isInitialized());
132 
133         CountDownLatch latch = new CountDownLatch(1);
134         mBinder.setPersonalizationStatus(true,
135                 new IOnDevicePersonalizationConfigServiceCallback.Stub() {
136                     @Override
137                     public void onSuccess() {
138                         latch.countDown();
139                     }
140 
141                     @Override
142                     public void onFailure(int errorCode) {
143                         latch.countDown();
144                     }
145                 });
146 
147         latch.await();
148         assertTrue(mUserPrivacyStatus.isPersonalizationStatusEnabled());
149 
150         assertEquals(0, mUserData.utcOffset);
151         assertFalse(mUserDataCollector.isInitialized());
152     }
153 
154     @Test
155     public void testSetPersonalizationStatusIfCallbackMissing() throws Exception {
156         assertThrows(NullPointerException.class, () -> {
157             mBinder.setPersonalizationStatus(true, null);
158         });
159     }
160 
161     @Test
162     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
163     public void testSetPersonalizationStatusThrowsRuntimeException() throws Exception {
164         when(mContext.getSystemService(any(Class.class))).thenThrow(RuntimeException.class);
165         CountDownLatch latch = new CountDownLatch(1);
166         TestCallback callback = new TestCallback(latch);
167 
168         mBinder.setPersonalizationStatus(true, callback);
169 
170         assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));
171         assertEquals(Constants.STATUS_INTERNAL_ERROR, callback.getErrCode());
172         verify(mMockClientErrorLogger)
173                 .logErrorWithExceptionInfo(
174                         isA(RuntimeException.class),
175                         eq(AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ON_DEVICE_PERSONALIZATION_ERROR),
176                         eq(AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__ODP));
177     }
178 
179     @Test
180     public void testSetPersonalizationStatusNoOps() throws Exception {
181         mUserPrivacyStatus.setPersonalizationStatusEnabled(true);
182 
183         populateUserData();
184         assertNotEquals(0, mUserData.utcOffset);
185         int utcOffset = mUserData.utcOffset;
186         assertTrue(mUserDataCollector.isInitialized());
187 
188         CountDownLatch latch = new CountDownLatch(1);
189         mBinder.setPersonalizationStatus(true,
190                 new IOnDevicePersonalizationConfigServiceCallback.Stub() {
191                     @Override
192                     public void onSuccess() {
193                         latch.countDown();
194                     }
195 
196                     @Override
197                     public void onFailure(int errorCode) {
198                         latch.countDown();
199                     }
200                 });
201 
202         latch.await();
203 
204         assertTrue(mUserPrivacyStatus.isPersonalizationStatusEnabled());
205         // Adult data should not be roll-back'ed
206         assertEquals(utcOffset, mUserData.utcOffset);
207         assertTrue(mUserDataCollector.isInitialized());
208     }
209 
210     @Test
211     public void testWithBoundService() throws TimeoutException {
212         Intent serviceIntent = new Intent(mContext,
213                 OnDevicePersonalizationConfigServiceImpl.class);
214         IBinder binder = serviceRule.bindService(serviceIntent);
215         assertTrue(binder instanceof OnDevicePersonalizationConfigServiceDelegate);
216     }
217 
218     @After
219     public void tearDown() throws Exception {
220         mUserDataCollector.clearUserData(mUserData);
221         mUserDataCollector.clearMetadata();
222     }
223 
224     private void populateUserData() {
225         mUserDataCollector.updateUserData(mUserData);
226     }
227 
228     class TestCallback extends IOnDevicePersonalizationConfigServiceCallback.Stub {
229 
230         int mErrCode;
231         CountDownLatch mLatch;
232 
233         TestCallback(CountDownLatch latch) {
234             this.mLatch = latch;
235         }
236 
237         @Override
238         public void onSuccess() {
239         }
240 
241         @Override
242         public void onFailure(int errorCode) {
243             mErrCode = errorCode;
244             mLatch.countDown();
245         }
246 
247         public int getErrCode() {
248             return mErrCode;
249         }
250     }
251 }
252