Home | History | Annotate | Download | only in tools
      1 /*
      2  * Copyright (C) 2017 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 android.app.cts.android.app.cts.tools;
     18 
     19 import android.app.ActivityManager;
     20 import android.app.Instrumentation;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.pm.ApplicationInfo;
     24 import android.content.pm.PackageManager;
     25 import android.os.IBinder;
     26 import android.os.Parcel;
     27 import android.os.RemoteException;
     28 
     29 import androidx.test.InstrumentationRegistry;
     30 
     31 import com.android.compatibility.common.util.SystemUtil;
     32 
     33 import java.io.IOException;
     34 
     35 /**
     36  * Helper for monitoring and controlling the state of a process under test.
     37  * Primarily currently a convenience for cleanly killing a process and waiting
     38  * for it to entirely disappear from the system.
     39  */
     40 public final class ServiceProcessController {
     41     final Context mContext;
     42     final Instrumentation mInstrumentation;
     43     final String mMyPackageName;
     44     final Intent[] mServiceIntents;
     45     final String mServicePackage;
     46     final long mDefaultWaitTime;
     47 
     48     final ActivityManager mAm;
     49     final Parcel mData;
     50     final ServiceConnectionHandler[] mConnections;
     51     final int mUid;
     52     final UidImportanceListener mUidForegroundListener;
     53     final UidImportanceListener mUidGoneListener;
     54     final WatchUidRunner mUidWatcher;
     55 
     56     public ServiceProcessController(Context context, Instrumentation instrumentation,
     57             String myPackageName, Intent[] serviceIntents)
     58             throws IOException, PackageManager.NameNotFoundException {
     59         this(context, instrumentation, myPackageName, serviceIntents, 5*1000);
     60     }
     61 
     62     public ServiceProcessController(Context context, Instrumentation instrumentation,
     63             String myPackageName, Intent[] serviceIntents, long defaultWaitTime)
     64             throws IOException, PackageManager.NameNotFoundException {
     65         mContext = context;
     66         mInstrumentation = instrumentation;
     67         mMyPackageName = myPackageName;
     68         mServiceIntents = serviceIntents;
     69         mServicePackage = mServiceIntents[0].getComponent().getPackageName();
     70         mDefaultWaitTime = defaultWaitTime;
     71 
     72         InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
     73                 mMyPackageName, android.Manifest.permission.PACKAGE_USAGE_STATS);
     74         /*
     75         Log.d("XXXX", "Invoke: " + cmd);
     76         Log.d("XXXX", "Result: " + result);
     77         Log.d("XXXX", SystemUtil.runShellCommand(getInstrumentation(), "dumpsys package "
     78                 + STUB_PACKAGE_NAME));
     79         */
     80 
     81         mAm = mContext.getSystemService(ActivityManager.class);
     82         mData = Parcel.obtain();
     83         mConnections = new ServiceConnectionHandler[serviceIntents.length];
     84         for (int i=0; i<serviceIntents.length; i++) {
     85             mConnections[i] = new ServiceConnectionHandler(mContext, serviceIntents[i],
     86                     mDefaultWaitTime);
     87         }
     88 
     89         ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfo(
     90                 mServicePackage, 0);
     91         mUid = appInfo.uid;
     92 
     93         mUidForegroundListener = new UidImportanceListener(mContext, appInfo.uid,
     94                 ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE, mDefaultWaitTime);
     95         mUidForegroundListener.register();
     96         mUidGoneListener = new UidImportanceListener(mContext, appInfo.uid,
     97                 ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY, mDefaultWaitTime);
     98         mUidGoneListener.register();
     99 
    100         mUidWatcher = new WatchUidRunner(instrumentation, appInfo.uid, mDefaultWaitTime);
    101     }
    102 
    103     public void denyBackgroundOp() throws IOException {
    104         denyBackgroundOp(mDefaultWaitTime);
    105     }
    106 
    107     public void denyBackgroundOp(long timeout) throws IOException {
    108         String cmd = "appops set " + mServicePackage + " RUN_IN_BACKGROUND deny";
    109         String result = SystemUtil.runShellCommand(mInstrumentation, cmd);
    110 
    111         // This is a side-effect of the app op command.
    112         mUidWatcher.expect(WatchUidRunner.CMD_IDLE, null, timeout);
    113         mUidWatcher.expect(WatchUidRunner.CMD_PROCSTATE, "NONE", timeout);
    114     }
    115 
    116     public void allowBackgroundOp() throws IOException {
    117         String cmd = "appops set " + mServicePackage + " RUN_IN_BACKGROUND allow";
    118         String result = SystemUtil.runShellCommand(mInstrumentation, cmd);
    119     }
    120 
    121     public void makeUidIdle() throws IOException {
    122         String cmd = "am make-uid-idle " + mServicePackage;
    123         String result = SystemUtil.runShellCommand(mInstrumentation, cmd);
    124     }
    125 
    126     public void removeFromWhitelist() throws IOException {
    127         String cmd = "cmd deviceidle whitelist -" + mServicePackage;
    128         String result = SystemUtil.runShellCommand(mInstrumentation, cmd);
    129     }
    130 
    131     public void addToWhitelist() throws IOException {
    132         String cmd = "cmd deviceidle whitelist +" + mServicePackage;
    133         String result = SystemUtil.runShellCommand(mInstrumentation, cmd);
    134     }
    135 
    136     public void tempWhitelist(long duration) throws IOException {
    137         String cmd = "cmd deviceidle tempwhitelist -d " + duration + " " + mServicePackage;
    138         String result = SystemUtil.runShellCommand(mInstrumentation, cmd);
    139     }
    140 
    141     public void removeFromTempWhitelist() throws IOException {
    142         String cmd = "cmd deviceidle tempwhitelist -r " + mServicePackage;
    143         SystemUtil.runShellCommand(mInstrumentation, cmd);
    144     }
    145 
    146     public void setAppOpMode(String opStr, String mode) throws IOException {
    147         String cmd = "cmd appops set " + mServicePackage + " " + opStr + "  " + mode;
    148         SystemUtil.runShellCommand(mInstrumentation, cmd);
    149     }
    150 
    151     public void cleanup() throws IOException {
    152         removeFromWhitelist();
    153         allowBackgroundOp();
    154         mUidWatcher.finish();
    155         mUidGoneListener.unregister();
    156         mUidForegroundListener.unregister();
    157         mData.recycle();
    158     }
    159 
    160     public ServiceConnectionHandler getConnection(int index) {
    161         return mConnections[index];
    162     }
    163 
    164     public int getUid() {
    165         return mUid;
    166     }
    167 
    168     public UidImportanceListener getUidForegroundListener() {
    169         return mUidForegroundListener;
    170     }
    171 
    172     public UidImportanceListener getUidGoneListener() {
    173         return mUidGoneListener;
    174     }
    175 
    176     public WatchUidRunner getUidWatcher() {
    177         return mUidWatcher;
    178     }
    179 
    180     public void ensureProcessGone() {
    181         ensureProcessGone(mDefaultWaitTime);
    182     }
    183 
    184     public void ensureProcessGone(long timeout) {
    185         for (int i=0; i<mConnections.length; i++) {
    186             mConnections[i].bind(timeout);
    187         }
    188 
    189         for (int i=0; i<mConnections.length; i++) {
    190             IBinder serviceBinder = mConnections[i].getServiceIBinder();
    191             mConnections[i].unbind(timeout);
    192             try {
    193                 serviceBinder.transact(IBinder.FIRST_CALL_TRANSACTION, mData, null, 0);
    194             } catch (RemoteException e) {
    195             }
    196         }
    197 
    198         // Wait for uid's process to go away.
    199         mUidGoneListener.waitForValue(ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE,
    200                 ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE, timeout);
    201         int importance = mAm.getPackageImportance(mServicePackage);
    202         if (importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE) {
    203             throw new IllegalStateException("Unexpected importance after killing process: "
    204                     + importance);
    205         }
    206         mUidWatcher.waitFor(WatchUidRunner.CMD_GONE, null, timeout);
    207     }
    208 }
    209