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