• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.bedstead.dpmwrapper;
17 
18 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
19 import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER;
20 
21 import static com.android.bedstead.dpmwrapper.DataFormatter.addArg;
22 import static com.android.bedstead.dpmwrapper.DataFormatter.getArg;
23 import static com.android.bedstead.dpmwrapper.Utils.ACTION_WRAPPED_MANAGER_CALL;
24 import static com.android.bedstead.dpmwrapper.Utils.EXTRA_CLASS;
25 import static com.android.bedstead.dpmwrapper.Utils.EXTRA_METHOD;
26 import static com.android.bedstead.dpmwrapper.Utils.EXTRA_NUMBER_ARGS;
27 import static com.android.bedstead.dpmwrapper.Utils.VERBOSE;
28 import static com.android.bedstead.dpmwrapper.Utils.getHandler;
29 
30 import android.annotation.Nullable;
31 import android.app.admin.DevicePolicyManager;
32 import android.content.BroadcastReceiver;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.content.pm.ActivityInfo;
36 import android.content.pm.PackageInfo;
37 import android.content.pm.PackageManager;
38 import android.content.pm.PackageManager.NameNotFoundException;
39 import android.net.TetheringManager;
40 import android.net.wifi.WifiManager;
41 import android.os.Build;
42 import android.os.Bundle;
43 import android.os.HardwarePropertiesManager;
44 import android.os.UserHandle;
45 import android.os.UserManager;
46 import android.util.Log;
47 
48 import com.android.compatibility.common.util.SystemUtil;
49 
50 import org.mockito.stubbing.Answer;
51 
52 import java.lang.reflect.InvocationTargetException;
53 import java.util.HashMap;
54 import java.util.Locale;
55 import java.util.concurrent.CountDownLatch;
56 import java.util.concurrent.TimeUnit;
57 import java.util.concurrent.atomic.AtomicReference;
58 
59 //TODO(b/176993670): STOPSHIP - it currently uses ordered broadcasts and a Mockito spy to implement
60 //the IPC between users, but before S is shipped it should be changed to use the connected apps SDK
61 //or the new CTS infrastructure.
62 /**
63  * Class used to create to provide a {@link DevicePolicyManager} implementation (and other managers
64  * that must be run by the device owner user) that automatically funnels calls between the user
65  * running the tests and the user that is the device owner.
66  */
67 public final class TestAppSystemServiceFactory {
68 
69     private static final String TAG = TestAppSystemServiceFactory.class.getSimpleName();
70 
71     private static final int RESULT_NOT_SENT_TO_ANY_RECEIVER = 108;
72     static final int RESULT_OK = 42;
73     static final int RESULT_EXCEPTION = 666;
74 
75     // Must be high enough to outlast long tests like NetworkLoggingTest, which waits up to
76     // 6 minutes for network monitoring events.
77     private static final long TIMEOUT_MS = TimeUnit.MINUTES.toMillis(10);
78 
79     // Caches whether the package declares the required receiver (otherwise each test would be
80     // querying package manager, which is expensive)
81     private static final HashMap<String, Boolean> sHasRequiredReceiver = new HashMap<>();
82 
83     /**
84      * Gets the proper {@link DevicePolicyManager} instance to be used by the test.
85      */
getDevicePolicyManager(Context context, Class<? extends BroadcastReceiver> receiverClass, boolean forDeviceOwner, boolean isSingleUserMode)86     public static DevicePolicyManager getDevicePolicyManager(Context context,
87             Class<? extends BroadcastReceiver> receiverClass, boolean forDeviceOwner,
88             boolean isSingleUserMode) {
89         return getSystemService(context, DevicePolicyManager.class, receiverClass, forDeviceOwner,
90                 isSingleUserMode);
91     }
92 
93     /**
94      * Gets the proper {@link DevicePolicyManager} instance to be used by the test.
95      */
getDevicePolicyManager(Context context, Class<? extends BroadcastReceiver> receiverClass, boolean forDeviceOwner)96     public static DevicePolicyManager getDevicePolicyManager(Context context,
97             Class<? extends BroadcastReceiver> receiverClass, boolean forDeviceOwner) {
98         return getDevicePolicyManager(context, receiverClass, forDeviceOwner,
99                 isSingleUser(context));
100     }
101 
102     /**
103      * Gets the proper {@link WifiManager} instance to be used by device owner tests.
104      */
getWifiManager(Context context, Class<? extends BroadcastReceiver> receiverClass, boolean isSingleUserMode)105     public static WifiManager getWifiManager(Context context,
106             Class<? extends BroadcastReceiver> receiverClass, boolean isSingleUserMode) {
107         return getSystemService(context, WifiManager.class, receiverClass,
108                 /* forDeviceOwner= */ true, isSingleUserMode);
109     }
110 
111     /**
112      * Gets the proper {@link WifiManager} instance to be used by device owner tests.
113      */
getWifiManager(Context context, Class<? extends BroadcastReceiver> receiverClass)114     public static WifiManager getWifiManager(Context context,
115             Class<? extends BroadcastReceiver> receiverClass) {
116         return getSystemService(context, WifiManager.class, receiverClass,
117                 /* forDeviceOwner= */ true, isSingleUser(context));
118     }
119 
120     /** Gets the proper {@link TetheringManager} instance to be used by device owner tests. */
getTetheringManager( Context context, Class<? extends BroadcastReceiver> receiverClass)121     public static TetheringManager getTetheringManager(
122             Context context, Class<? extends BroadcastReceiver> receiverClass) {
123         return getSystemService(
124                 context,
125                 TetheringManager.class,
126                 receiverClass,
127                 /* forDeviceOwner= */ true,
128                 isSingleUser(context));
129     }
130 
isSingleUser(Context context)131     private static boolean isSingleUser(Context context) {
132         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM
133                 && SystemUtil.runWithShellPermissionIdentity(() ->
134                 context.getSystemService(DevicePolicyManager.class).getHeadlessDeviceOwnerMode()
135                         == HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER);
136     }
137 
138     /**
139      * Gets the proper {@link HardwarePropertiesManager} instance to be used by device owner tests.
140      */
getHardwarePropertiesManager(Context context, Class<? extends BroadcastReceiver> receiverClass)141     public static HardwarePropertiesManager getHardwarePropertiesManager(Context context,
142             Class<? extends BroadcastReceiver> receiverClass) {
143         return getSystemService(context, HardwarePropertiesManager.class, receiverClass,
144                 /* forDeviceOwner= */ true, isSingleUser(context));
145     }
146 
147     /**
148      * Gets the proper {@link UserManager} instance to be used by device owner tests.
149      */
getUserManager(Context context, Class<? extends BroadcastReceiver> receiverClass)150     public static UserManager getUserManager(Context context,
151             Class<? extends BroadcastReceiver> receiverClass) {
152         return getSystemService(context, UserManager.class, receiverClass,
153                 /* forDeviceOwner= */ true, isSingleUser(context));
154     }
155 
156     /**
157      * Gets the proper {@link GenericManager} instance to be used by the test.
158      */
getGenericManager(Context context, Class<? extends BroadcastReceiver> receiverClass)159     public static GenericManager getGenericManager(Context context,
160             Class<? extends BroadcastReceiver> receiverClass) {
161         return getSystemService(context, GenericManager.class, receiverClass,
162                 /* forDeviceOwner= */ true, isSingleUser(context));
163     }
164 
assertHasRequiredReceiver(Context context)165     private static void assertHasRequiredReceiver(Context context) {
166         if (!Utils.isHeadlessSystemUserMode()) return;
167 
168         String packageName = context.getPackageName();
169         Boolean hasIt = sHasRequiredReceiver.get(packageName);
170         if (hasIt != null && hasIt) {
171             return;
172         }
173         PackageManager pm = context.getPackageManager();
174         Class<?> targetClass = TestAppCallbacksReceiver.class;
175         PackageInfo packageInfo;
176         try {
177             packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_RECEIVERS);
178         } catch (NameNotFoundException e) {
179             Log.wtf(TAG, "Could not get receivers for " + packageName);
180             return;
181         }
182 
183         int numberReceivers = (packageInfo.receivers == null ? 0 : packageInfo.receivers.length);
184         Log.d(TAG, "assertHasRequiredReceiver(" + packageName + "): userId=" + context.getUserId()
185                 + ", info=" + packageInfo + ", receivers=" + numberReceivers);
186 
187         if (packageInfo.receivers != null) {
188             for (ActivityInfo receiver : packageInfo.receivers) {
189                 Log.v(TAG, "checking receiver " + receiver);
190                 Class<?> receiverClass = null;
191                 try {
192                     receiverClass = Class.forName(receiver.name);
193                 } catch (ClassNotFoundException e) {
194                     Log.e(TAG, "Invalid receiver class on manifest: " + receiver.name);
195                     continue;
196                 }
197                 if (TestAppCallbacksReceiver.class.isAssignableFrom(receiverClass)) {
198                     Log.d(TAG, "Found " + receiverClass.getName() + " on " + packageName);
199                     sHasRequiredReceiver.put(packageName, Boolean.TRUE);
200                     return;
201                 }
202             }
203         }
204         if (numberReceivers == 0) {
205             // This is happening sometimes on headless system user; most likely it's a permission
206             // issue querying pm, but given that the DpmWrapper is temporary and this check is more
207             // of a validation to avoid other issues, it's ok to just log...
208             Log.wtf(TAG, "Package " + packageName + " has no receivers");
209             return;
210         }
211         fail("Package " + packageName + " has " + numberReceivers + " receivers, but not extends "
212                 + TestAppCallbacksReceiver.class.getName() + " - did you add one to the manifest?");
213     }
214 
getSystemService(Context context, Class<T> serviceClass, Class<? extends BroadcastReceiver> receiverClass, boolean forDeviceOwner, boolean isSingleUserMode)215     private static <T> T getSystemService(Context context, Class<T> serviceClass,
216             Class<? extends BroadcastReceiver> receiverClass, boolean forDeviceOwner,
217             boolean isSingleUserMode) {
218         ServiceManagerWrapper<T> wrapper = null;
219         Class<?> wrappedClass;
220 
221         @SuppressWarnings("unchecked")
222         T manager = null;
223         boolean managerCanBeNull = false;
224 
225         if (serviceClass.equals(DevicePolicyManager.class)) {
226             wrappedClass = DevicePolicyManager.class;
227             @SuppressWarnings("unchecked")
228             ServiceManagerWrapper<T> safeCastWrapper =
229                     (ServiceManagerWrapper<T>) new DevicePolicyManagerWrapper();
230             wrapper = safeCastWrapper;
231         } else if (serviceClass.equals(WifiManager.class)) {
232             @SuppressWarnings("unchecked")
233             ServiceManagerWrapper<T> safeCastWrapper =
234                     (ServiceManagerWrapper<T>) new WifiManagerWrapper();
235             wrapper = safeCastWrapper;
236             wrappedClass = WifiManager.class;
237             managerCanBeNull = true;
238         } else if (serviceClass.equals(TetheringManager.class)) {
239             @SuppressWarnings("unchecked")
240             ServiceManagerWrapper<T> safeCastWrapper =
241                     (ServiceManagerWrapper<T>) new TetheringManagerWrapper();
242             wrapper = safeCastWrapper;
243             wrappedClass = TetheringManager.class;
244             managerCanBeNull = true;
245         } else if (serviceClass.equals(HardwarePropertiesManager.class)) {
246             @SuppressWarnings("unchecked")
247             ServiceManagerWrapper<T> safeCastWrapper =
248                     (ServiceManagerWrapper<T>) new HardwarePropertiesManagerWrapper();
249             wrapper = safeCastWrapper;
250             wrappedClass = HardwarePropertiesManager.class;
251         } else if (serviceClass.equals(UserManager.class)) {
252             @SuppressWarnings("unchecked")
253             ServiceManagerWrapper<T> safeCastWrapper =
254                     (ServiceManagerWrapper<T>) new UserManagerWrapper();
255             wrapper = safeCastWrapper;
256             wrappedClass = UserManager.class;
257         } else if (serviceClass.equals(GenericManager.class)) {
258             @SuppressWarnings("unchecked")
259             ServiceManagerWrapper<T> safeCastWrapper =
260                     (ServiceManagerWrapper<T>) new GenericManagerWrapper();
261             @SuppressWarnings("unchecked")
262             T safeCastManager = (T) new GenericManagerImpl(context);
263             wrapper = safeCastWrapper;
264             wrappedClass = GenericManager.class;
265             manager = safeCastManager;
266         } else {
267             throw new IllegalArgumentException("invalid service class: " + serviceClass);
268         }
269         if (manager == null) {
270             manager = (T) context.getSystemService(wrappedClass);
271         }
272 
273         if (manager == null) {
274             if (managerCanBeNull) {
275                 Log.i(TAG, "Manager of" + serviceClass + "is null");
276                 return null;
277             }
278             fail("Could not get a manager of type " + serviceClass);
279         }
280 
281         if (!forDeviceOwner) return manager;
282 
283         assertHasRequiredReceiver(context);
284 
285         int userId = context.getUserId();
286         if (userId == UserHandle.USER_SYSTEM || !Utils.isHeadlessSystemUserMode()
287                 || isSingleUserMode) {
288             Log.i(TAG, "get(): returning 'pure' DevicePolicyManager for user " + userId);
289             return manager;
290         }
291 
292         String receiverClassName = receiverClass.getName();
293         final String wrappedClassName = wrappedClass.getName();
294         if (VERBOSE) {
295             Log.v(TAG, "get(): receiverClassName: " + receiverClassName
296                     + ", wrappedClassName: " + wrappedClassName);
297         }
298 
299         Answer<?> answer = (inv) -> {
300             Object[] args = inv.getArguments();
301             if (VERBOSE) {
302                 Log.v(TAG, "spying " + inv + " method: " + inv.getMethod());
303             } else {
304                 Log.i(TAG, "spying " + inv.getMethod());
305             }
306             String methodName = inv.getMethod().getName();
307             Intent intent = new Intent(ACTION_WRAPPED_MANAGER_CALL)
308                     .setClassName(context, receiverClassName)
309                     .putExtra(EXTRA_CLASS, wrappedClassName)
310                     .putExtra(EXTRA_METHOD, methodName)
311                     .putExtra(EXTRA_NUMBER_ARGS, args.length);
312             for (int i = 0; i < args.length; i++) {
313                 addArg(intent, args, i);
314             }
315 
316             final CountDownLatch latch = new CountDownLatch(1);
317             final AtomicReference<Result> resultRef = new AtomicReference<>();
318             BroadcastReceiver myReceiver = new BroadcastReceiver() {
319                 public void onReceive(Context context, Intent intent) {
320                     String action = intent.getAction();
321                     if (VERBOSE) {
322                         Log.v(TAG, "spy received intent " + action + " for user "
323                                 + context.getUserId());
324                     }
325                     Result result = new Result(this);
326                     if (VERBOSE) Log.v(TAG, "result:" + result);
327                     resultRef.set(result);
328                     latch.countDown();
329                 };
330 
331             };
332             if (VERBOSE) {
333                 Log.v(TAG, "Sending ordered broadcast (" + Utils.toString(intent) + ") from user "
334                         + userId + " to user " + UserHandle.SYSTEM);
335             }
336 
337             // NOTE: method below used to be wrapped under runWithShellPermissionIdentity() to get
338             // INTERACT_ACROSS_USERS permission, but that's not needed anymore (as the permission
339             // is granted by the test. Besides, this class is now also used by DO apps that are not
340             // instrumented, so it was removed
341             if (context.checkSelfPermission(INTERACT_ACROSS_USERS)
342                     != PackageManager.PERMISSION_GRANTED) {
343                 fail("Package " + context.getPackageName() + " doesn't have "
344                         + INTERACT_ACROSS_USERS + " - did you add it to the manifest and called "
345                         + "grantDpmWrapper() (for user " + userId + ") in the host-side test?");
346             }
347             context.sendOrderedBroadcastAsUser(intent,
348                     UserHandle.SYSTEM, /* permission= */ null, myReceiver, getHandler(),
349                     RESULT_NOT_SENT_TO_ANY_RECEIVER, /* initialData= */ null,
350                     /* initialExtras= */ null);
351 
352             if (VERBOSE) {
353                 Log.d(TAG, "Waiting up to " + TIMEOUT_MS + "ms for response on "
354                         + Thread.currentThread());
355             }
356             if (!latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
357                 fail("Ordered broadcast for %s() not received in %dms", methodName, TIMEOUT_MS);
358             }
359 
360             Result result = resultRef.get();
361             Log.d(TAG, "Received result on user " + userId + ". Code: "
362                     + resultCodeToString(result.code));
363 
364             if (VERBOSE) {
365                 // Some results - like network logging events - are quite large
366                 Log.v(TAG, "Result: " + result);
367             }
368 
369             switch (result.code) {
370                 case RESULT_OK:
371                     return result.value;
372                 case RESULT_EXCEPTION:
373                     Exception e = (Exception) result.value;
374                     throw (e instanceof InvocationTargetException) ? e.getCause() : e;
375                 case RESULT_NOT_SENT_TO_ANY_RECEIVER:
376                     fail("Didn't receive result from ordered broadcast - did you override "
377                             + receiverClassName + ".onReceive() to call "
378                             + "DeviceOwnerHelper.runManagerMethod()? Did you add "
379                             + ACTION_WRAPPED_MANAGER_CALL + " to its intent filter / manifest?");
380                     return null;
381                 default:
382                     fail("Received invalid result for method %s: %s", methodName, result);
383                     return null;
384             }
385         };
386 
387         T spy = wrapper.getWrapper(context, manager, answer);
388 
389         return spy;
390 
391     }
392 
resultCodeToString(int code)393     static String resultCodeToString(int code) {
394         // Can't use DebugUtils.constantToString() because some valus are private
395         switch (code) {
396             case RESULT_NOT_SENT_TO_ANY_RECEIVER:
397                 return "RESULT_NOT_SENT_TO_ANY_RECEIVER";
398             case RESULT_OK:
399                 return "RESULT_OK";
400             case RESULT_EXCEPTION:
401                 return "RESULT_EXCEPTION";
402             default:
403                 return "RESULT_UNKNOWN:" + code;
404         }
405     }
406 
fail(String template, Object... args)407     private static void fail(String template, Object... args) {
408         throw new AssertionError(String.format(Locale.ENGLISH, template, args));
409     }
410 
411     private static final class Result {
412         public final int code;
413         @Nullable public final String error;
414         @Nullable public final Bundle extras;
415         @Nullable public final Object value;
416 
Result(BroadcastReceiver receiver)417         Result(BroadcastReceiver receiver) {
418             int resultCode = receiver.getResultCode();
419             String data = receiver.getResultData();
420             extras = receiver.getResultExtras(/* makeMap= */ true);
421             Object parsedValue = null;
422             try {
423                 if (extras != null && !extras.isEmpty()) {
424                     Object[] result = new Object[1];
425                     int index = 0;
426                     getArg(extras, result, /* parameterTypes= */ null, index);
427                     parsedValue = result[index];
428                 }
429             } catch (Exception e) {
430                 Log.e(TAG, "error parsing extras (code=" + resultCode + ", data=" + data, e);
431                 data = "error parsing extras";
432                 resultCode = RESULT_EXCEPTION;
433             }
434             code = resultCode;
435             error = data;
436             value = parsedValue;
437         }
438 
439         @Override
toString()440         public String toString() {
441             return "Result[code=" + resultCodeToString(code) + ", error=" + error
442                     + ", extras=" + extras + ", value=" + value + "]";
443         }
444     }
445 
446     abstract static class ServiceManagerWrapper<T> {
getWrapper(Context context, T manager, Answer<?> answer)447         abstract T getWrapper(Context context, T manager, Answer<?> answer);
448     }
449 
TestAppSystemServiceFactory()450     private TestAppSystemServiceFactory() {
451         throw new UnsupportedOperationException("contains only static methods");
452     }
453 }
454