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.bedstead.testapp;
18 
19 import android.accounts.AccountManager;
20 import android.accounts.RemoteAccountManager;
21 import android.accounts.RemoteAccountManagerWrapper;
22 import android.app.NotificationManager;
23 import android.app.RemoteNotificationManager;
24 import android.app.RemoteNotificationManagerWrapper;
25 import android.app.RemoteWallpaperManager;
26 import android.app.RemoteWallpaperManagerWrapper;
27 import android.app.WallpaperManager;
28 import android.app.admin.DevicePolicyManager;
29 import android.app.admin.RemoteDevicePolicyManager;
30 import android.app.admin.RemoteDevicePolicyManagerWrapper;
31 import android.bluetooth.BluetoothManager;
32 import android.bluetooth.RemoteBluetoothManager;
33 import android.bluetooth.RemoteBluetoothManagerWrapper;
34 import android.content.BroadcastReceiver;
35 import android.content.Context;
36 import android.content.IntentFilter;
37 import android.content.RemoteContext;
38 import android.content.RemoteContextWrapper;
39 import android.content.RemoteRestrictionsManager;
40 import android.content.RemoteRestrictionsManagerWrapper;
41 import android.content.pm.CrossProfileApps;
42 import android.content.pm.PackageManager;
43 import android.content.pm.RemoteCrossProfileApps;
44 import android.content.pm.RemoteCrossProfileAppsWrapper;
45 import android.content.pm.RemoteLauncherApps;
46 import android.content.pm.RemoteLauncherAppsWrapper;
47 import android.content.pm.RemotePackageManager;
48 import android.content.pm.RemotePackageManagerWrapper;
49 import android.media.projection.RemoteMediaProjectionManager;
50 import android.media.projection.RemoteMediaProjectionManagerWrapper;
51 import android.net.wifi.RemoteWifiManager;
52 import android.net.wifi.RemoteWifiManagerWrapper;
53 import android.net.wifi.WifiManager;
54 import android.os.HardwarePropertiesManager;
55 import android.os.RemoteHardwarePropertiesManager;
56 import android.os.RemoteHardwarePropertiesManagerWrapper;
57 import android.os.RemoteUserManager;
58 import android.os.RemoteUserManagerWrapper;
59 import android.os.UserManager;
60 import android.security.KeyChain;
61 import android.security.RemoteKeyChain;
62 import android.security.RemoteKeyChainWrapper;
63 import android.telecom.RemoteTelecomManager;
64 import android.telecom.RemoteTelecomManagerWrapper;
65 import android.telephony.RemoteSmsManager;
66 import android.telephony.RemoteSmsManagerWrapper;
67 import android.telephony.RemoteTelephonyManager;
68 import android.telephony.RemoteTelephonyManagerWrapper;
69 import android.telephony.euicc.RemoteEuiccManager;
70 import android.telephony.euicc.RemoteEuiccManagerWrapper;
71 
72 import com.android.bedstead.nene.TestApis;
73 import com.android.bedstead.nene.appops.AppOps;
74 import com.android.bedstead.nene.exceptions.NeneException;
75 import com.android.bedstead.nene.packages.Package;
76 import com.android.bedstead.nene.packages.ProcessReference;
77 import com.android.bedstead.nene.users.UserReference;
78 
79 import com.google.android.enterprise.connectedapps.ConnectionListener;
80 import com.google.android.enterprise.connectedapps.ProfileConnectionHolder;
81 import com.google.android.enterprise.connectedapps.exceptions.UnavailableProfileException;
82 import com.google.errorprone.annotations.CanIgnoreReturnValue;
83 
84 import java.util.HashMap;
85 import java.util.Map;
86 import java.util.Objects;
87 import java.util.UUID;
88 
89 import javax.annotation.Nullable;
90 
91 /**
92  * A reference to a specific instance of a {@link TestApp} on a given user.
93  *
94  * <p>The user may not exist, or the test app may not be installed on the user.
95  */
96 public class TestAppInstance implements AutoCloseable, ConnectionListener {
97 
98     private final TestApp mTestApp;
99     private final UserReference mUser;
100     private final TestAppConnector mConnector;
101     private final Map<IntentFilter, Long> mRegisteredBroadcastReceivers = new HashMap<>();
102     private final ProfileTestAppController mTestAppController;
103     private final TestAppActivities mTestAppActivities;
104     private boolean mKeepAliveManually = false;
105     private ProfileConnectionHolder mConnectionHolder = null;
106     private final TestAppInstancePermissions mTestAppInstancePermissions =
107             new TestAppInstancePermissions(this);
108 
109     /**
110      * Use {@link TestApp#install} or {@link TestApp#instance} to get an instance of
111      * {@link TestAppInstance}.
112      */
TestAppInstance(TestApp testApp, UserReference user)113     public TestAppInstance(TestApp testApp, UserReference user) {
114         if (testApp == null || user == null) {
115             throw new NullPointerException();
116         }
117         mTestApp = testApp;
118         mUser = user;
119         mConnector = TestAppConnector.create(TestApis.context().instrumentedContext(),
120                 new TestAppBinder(this));
121         mConnector.addConnectionListener(this);
122         mTestAppController =
123                 ProfileTestAppController.create(mConnector);
124         mTestAppActivities = TestAppActivities.create(this);
125     }
126 
connector()127     TestAppConnector connector() {
128         return mConnector;
129     }
130 
131     /**
132      * Access activities on the test app.
133      */
activities()134     public TestAppActivities activities() {
135         return mTestAppActivities;
136     }
137 
138     /**
139      * The {@link TestApp} this instance refers to.
140      */
testApp()141     public TestApp testApp() {
142         return mTestApp;
143     }
144 
145     /**
146      * See {@link TestApp#packageName()}.
147      */
packageName()148     public String packageName() {
149        return testApp().packageName();
150     }
151 
152     /**
153      * The {@link UserReference} this instance refers to.
154      */
user()155     public UserReference user() {
156         return mUser;
157     }
158 
159     /**
160      * The {@link Package} of the {@link TestApp} this instance refers to.
161      */
pkg()162     public Package pkg() {
163         return Package.of(packageName());
164     }
165 
166     /**
167      * Uninstall the {@link TestApp} from the user referenced by
168      * this {@link TestAppInstance}.
169      */
uninstall()170     public void uninstall() {
171         mTestApp.uninstall(mUser);
172     }
173 
174     /**
175      * Register a {@link BroadcastReceiver} for a given {@link IntentFilter}.
176      *
177      * <p>A new {@link BroadcastReceiver} instance will be created for each {@link IntentFilter}.
178      *
179      * <p>Note that {@link IntentFilter} does not override {@code equals} and one broadcast receiver
180      * will be registered for each instance of {@link IntentFilter} regardless of the content of the
181      * {@link IntentFilter}.
182      *
183      * <p>As registered receivers are only active while the application is open, calling this method
184      * will have the same effect as calling {@link #keepAlive()}.
185      */
registerReceiver(IntentFilter intentFilter)186     public void registerReceiver(IntentFilter intentFilter) {
187         registerReceiver(intentFilter, 0);
188     }
189 
190     /**
191      * See {@link registerReceiver(IntentFilter)}.
192      */
registerReceiver(IntentFilter intentFilter, int flags)193     public void registerReceiver(IntentFilter intentFilter, int flags) {
194         if (mRegisteredBroadcastReceivers.containsKey(intentFilter)) {
195             return;
196         }
197 
198         long receiverId = UUID.randomUUID().getMostSignificantBits();
199         registerReceiver(intentFilter, receiverId, flags);
200         keepAlive(/* manualKeepAlive= */ false);
201     }
202 
registerReceiver(IntentFilter intentFilter, long receiverId)203     private void registerReceiver(IntentFilter intentFilter, long receiverId) {
204         registerReceiver(intentFilter, receiverId, 0);
205     }
206 
registerReceiver(IntentFilter intentFilter, long receiverId, int flags)207     private void registerReceiver(IntentFilter intentFilter, long receiverId, int flags) {
208         try (ProfileConnectionHolder h = mConnector.connect()){
209             mTestAppController.other().registerReceiver(receiverId, intentFilter, flags);
210             mRegisteredBroadcastReceivers.put(intentFilter, receiverId);
211         } catch (UnavailableProfileException e) {
212             throw new IllegalStateException("Could not connect to test app", e);
213         }
214     }
215 
216     /**
217      * Unregister the receiver
218      */
unregisterReceiver(IntentFilter intentFilter)219     public TestAppInstance unregisterReceiver(IntentFilter intentFilter) {
220         if (!mRegisteredBroadcastReceivers.containsKey(intentFilter)) {
221             return this;
222         }
223 
224         long receiverId = mRegisteredBroadcastReceivers.remove(intentFilter);
225 
226         try (ProfileConnectionHolder h = mConnector.connect()){
227             mTestAppController.other().unregisterReceiver(receiverId);
228             mRegisteredBroadcastReceivers.put(intentFilter, receiverId);
229         } catch (UnavailableProfileException e) {
230             throw new IllegalStateException("Could not connect to test app", e);
231         }
232 
233         if (mRegisteredBroadcastReceivers.isEmpty() && !mKeepAliveManually) {
234             stopKeepAlive();
235         }
236 
237         return this;
238     }
239 
240     /**
241      * Starts keeping the test app process alive.
242      *
243      * <p>This ensures that it will receive broadcasts using registered broadcast receivers.
244      *
245      * @see {@link #stopKeepAlive()}.
246      */
keepAlive()247     public TestAppInstance keepAlive() {
248         keepAlive(/* manualKeepAlive=*/ true);
249         return this;
250     }
251 
252     /**
253      * Starts keep alive mode and marks it as manual so that it won't be automatically ended if
254      * the last broadcast receiver is unregistered.
255      */
keepAlive(boolean manualKeepAlive)256     private void keepAlive(boolean manualKeepAlive) {
257         mKeepAliveManually = manualKeepAlive;
258         try {
259             if (mConnectionHolder != null) {
260                 mConnectionHolder.close();
261                 mConnectionHolder = null;
262             }
263 
264             mConnectionHolder = connector().connect();
265         } catch (UnavailableProfileException e) {
266             throw new IllegalStateException("Could not connect to test app. Is it installed?", e);
267         }
268     }
269 
270     /**
271      * Stops keeping the target app alive.
272      *
273      * <p>This will not kill the app immediately. To do that see {@link #stop()}.
274      */
275     @CanIgnoreReturnValue
stopKeepAlive()276     public TestAppInstance stopKeepAlive() {
277         mKeepAliveManually = false;
278         if (mConnectionHolder != null) {
279             mConnectionHolder.close();
280             mConnectionHolder = null;
281         }
282         return this;
283     }
284 
285     /**
286      * Immediately force stops the app.
287      *
288      * <p>This will also stop keeping the target app alive (see {@link #stopKeepAlive()}.
289      */
290     @CanIgnoreReturnValue
stop()291     public TestAppInstance stop() {
292         stopKeepAlive();
293 
294         ProcessReference process = mTestApp.pkg().runningProcess(mUser);
295         if (process != null) {
296             try {
297                 process.kill();
298             } catch (NeneException e) {
299                 throw new NeneException("Error killing process... process is " + process(), e);
300             }
301         }
302 
303         return this;
304     }
305 
306     /**
307      * Gets the {@link ProcessReference} of the app, if any.
308      */
309     @Nullable
process()310     public ProcessReference process() {
311         return mTestApp.pkg().runningProcess(mUser);
312     }
313 
314     @Override
close()315     public void close() {
316         stopKeepAlive();
317         uninstall();
318     }
319 
320     @Override
connectionChanged()321     public void connectionChanged() {
322         if (mConnector.isConnected()) {
323             // re-register broadcast receivers when re-connected
324             for (Map.Entry<IntentFilter, Long> entry : mRegisteredBroadcastReceivers.entrySet()) {
325                 registerReceiver(entry.getKey(), entry.getValue());
326             }
327         }
328     }
329 
330     /** Access events related to this test app. */
events()331     public TestAppEvents events() {
332         return new TestAppEvents(this);
333     }
334 
335     /**
336      * Access {@link DevicePolicyManager} using this test app.
337      *
338      * <p>Almost all methods are available. Those that are not will be missing from the interface.
339      */
devicePolicyManager()340     public RemoteDevicePolicyManager devicePolicyManager() {
341         return new RemoteDevicePolicyManagerWrapper(mConnector, mUser, mTestApp.pkg());
342     }
343 
344     /**
345      * Access {@link UserManager} using this test app.
346      *
347      * <p>Almost all methods are available. Those that are not will be missing from the interface.
348      */
userManager()349     public RemoteUserManager userManager() {
350         return new RemoteUserManagerWrapper(mConnector, mUser, mTestApp.pkg());
351     }
352 
353     /**
354      * Access {@link WifiManager} using this test app.
355      *
356      * <p>Almost all methods are available. Those that are not will be missing from the interface.
357      */
wifiManager()358     public RemoteWifiManager wifiManager() {
359         return new RemoteWifiManagerWrapper(mConnector, mUser, mTestApp.pkg());
360     }
361 
362     /**
363      * Access {@link HardwarePropertiesManager} using this test app.
364      *
365      * <p>Almost all methods are available. Those that are not will be missing from the interface.
366      */
hardwarePropertiesManager()367     public RemoteHardwarePropertiesManager hardwarePropertiesManager() {
368         return new RemoteHardwarePropertiesManagerWrapper(mConnector, mUser, mTestApp.pkg());
369     }
370 
371     /**
372      * Access {@link PackageManager} using this test app.
373      *
374      * <p>Almost all methods are available. Those that are not will be missing from the interface.
375      */
packageManager()376     public RemotePackageManager packageManager() {
377         return new RemotePackageManagerWrapper(mConnector, mUser, mTestApp.pkg());
378     }
379 
380     /**
381      * Access {@link CrossProfileApps} using this test app.
382      *
383      * <p>Almost all methods are available. Those that are not will be missing from the interface.
384      */
crossProfileApps()385     public RemoteCrossProfileApps crossProfileApps() {
386         return new RemoteCrossProfileAppsWrapper(mConnector, mUser, mTestApp.pkg());
387     }
388 
389     /**
390      * Access {@link android.content.pm.LauncherApps} using this test app.
391      *
392      * <p>Almost all methods are available. Those that are not will be missing from the interface.
393      */
launcherApps()394     public RemoteLauncherApps launcherApps() {
395         return new RemoteLauncherAppsWrapper(mConnector, mUser, mTestApp.pkg());
396     }
397 
398     /**
399      * Access {@link AccountManager} using this test app.
400      *
401      * <p>Almost all methods are available. Those that are not will be missing from the interface.
402      */
accountManager()403     public RemoteAccountManager accountManager() {
404         return new RemoteAccountManagerWrapper(mConnector, mUser, mTestApp.pkg());
405     }
406 
407     /**
408      * Access the application {@link Context} using this test app.
409      *
410      * <p>Almost all methods are available. Those that are not will be missing from the interface.
411      */
context()412     public RemoteContext context() {
413         return new RemoteContextWrapper(mConnector, mUser, mTestApp.pkg());
414     }
415 
416     /**
417      * Access the {@link KeyChain} using this test app.
418      *
419      * <p>Almost all methods are available. Those that are not will be missing from the interface.
420      */
keyChain()421     public RemoteKeyChain keyChain() {
422         return new RemoteKeyChainWrapper(mConnector, mUser, mTestApp.pkg());
423     }
424 
425     /**
426      * Access the {@link BluetoothManager} using this test app.
427      *
428      * <p>Almost all methods are available. Those that are not will be missing from the interface.
429      */
bluetoothManager()430     public RemoteBluetoothManager bluetoothManager() {
431         return new RemoteBluetoothManagerWrapper(mConnector, mUser, mTestApp.pkg());
432     }
433 
434     /**
435      * Access the {@link NotificationManager} using this test app.
436      *
437      * <p>Almost all methods are available. Those that are not will be missing from the interface.
438      */
notificationManager()439     public RemoteNotificationManager notificationManager() {
440         return new RemoteNotificationManagerWrapper(mConnector, mUser, mTestApp.pkg());
441     }
442 
443     /**
444      * Access the {@link android.telephony.SmsManager} using this test app.
445      *
446      * <p>Almost all methods are available. Those that are not will be missing from the interface.
447      */
smsManager()448     public RemoteSmsManager smsManager() {
449         return new RemoteSmsManagerWrapper(mConnector, mUser, mTestApp.pkg());
450     }
451 
452     /**
453      * Access the {@link TelecomManager} using this test app.
454      *
455      * <p>Almost all methods are available. Those that are not will be missing from the interface.
456      */
telecomManager()457     public RemoteTelecomManager telecomManager() {
458         return new RemoteTelecomManagerWrapper(mConnector, mUser, mTestApp.pkg());
459     }
460 
461     /**
462      * Access the {@link android.content.RestrictionsManager} using this test app.
463      *
464      * <p>Almost all methods are available. Those that are not will be missing from the interface.
465      */
restrictionsManager()466     public RemoteRestrictionsManager restrictionsManager() {
467         return new RemoteRestrictionsManagerWrapper(mConnector, mUser, mTestApp.pkg());
468     }
469 
470     /**
471      * Access {@link WallpaperManager} using this test app.
472      *
473      * <p>Almost all methods are available. Those that are not will be missing from the interface.
474      */
wallpaperManager()475     public RemoteWallpaperManager wallpaperManager() {
476         return new RemoteWallpaperManagerWrapper(mConnector, mUser, mTestApp.pkg());
477     }
478 
479     /**
480      * Access the {@link android.telephony.TelephonyManager} using this test app.
481      *
482      * <p>Almost all methods are available. Those that are not will be missing from the interface.
483      */
telephonyManager()484     public RemoteTelephonyManager telephonyManager() {
485         return new RemoteTelephonyManagerWrapper(mConnector, mUser, mTestApp.pkg());
486     }
487 
488     /**
489      * Access the {@link android.telephony.euicc.EuiccManager} using this test app.
490      *
491      * <p> Almost all methods are available. Those that are not will be missing from the interface.
492      */
euiccManager()493     public RemoteEuiccManager euiccManager() {
494         return new RemoteEuiccManagerWrapper(mConnector, mUser, mTestApp.pkg());
495     }
496 
497     /**
498      * Access the {@link android.media.projection.MediaProjectionManager} using this test app.
499      *
500      * <p>Almost all methods are available. Those that are not will be missing from the interface.
501      */
mediaProjectionManager()502     public RemoteMediaProjectionManager mediaProjectionManager() {
503         return new RemoteMediaProjectionManagerWrapper(mConnector, mUser, mTestApp.pkg());
504     }
505 
506     /**
507      * Access permissions for this test app.
508      */
permissions()509     public TestAppInstancePermissions permissions() {
510         return mTestAppInstancePermissions;
511     }
512 
513     /**
514      * Access AppOps for this test app.
515      */
appOps()516     public AppOps appOps() {
517         return testApp().pkg().appOps(mUser);
518     }
519 
520     @Override
toString()521     public String toString() {
522         return "TestAppInstance{"
523                 + "testApp=" + mTestApp
524                 + ", user=" + mUser
525                 + ", registeredBroadcastReceivers=" + mRegisteredBroadcastReceivers
526                 + ", keepAliveManually=" + mKeepAliveManually
527                 + '}';
528     }
529 
530     @Override
equals(Object o)531     public boolean equals(Object o) {
532         if (this == o) return true;
533         if (!(o instanceof TestAppInstance)) return false;
534         TestAppInstance that = (TestAppInstance) o;
535         return mTestApp.equals(that.mTestApp) && mUser.equals(that.mUser);
536     }
537 
538     @Override
hashCode()539     public int hashCode() {
540         return Objects.hash(mTestApp, mUser);
541     }
542 }
543