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 ServiceProcessController(Context context, Instrumentation instrumentation, String myPackageName, Intent[] serviceIntents)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 ServiceProcessController(Context context, Instrumentation instrumentation, String myPackageName, Intent[] serviceIntents, long defaultWaitTime)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 denyBackgroundOp()103 public void denyBackgroundOp() throws IOException { 104 denyBackgroundOp(mDefaultWaitTime); 105 } 106 denyBackgroundOp(long timeout)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 allowBackgroundOp()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 /** The "battery restriction" forced app standby app-op */ denyAnyInBackgroundOp()122 public void denyAnyInBackgroundOp() throws IOException { 123 String cmd = "appops set " + mServicePackage + " RUN_ANY_IN_BACKGROUND deny"; 124 String result = SystemUtil.runShellCommand(mInstrumentation, cmd); 125 } 126 allowAnyInBackgroundOp()127 public void allowAnyInBackgroundOp() throws IOException { 128 String cmd = "appops set " + mServicePackage + " RUN_ANY_IN_BACKGROUND allow"; 129 String result = SystemUtil.runShellCommand(mInstrumentation, cmd); 130 } 131 makeUidIdle()132 public void makeUidIdle() throws IOException { 133 String cmd = "am make-uid-idle " + mServicePackage; 134 String result = SystemUtil.runShellCommand(mInstrumentation, cmd); 135 } 136 removeFromWhitelist()137 public void removeFromWhitelist() throws IOException { 138 String cmd = "cmd deviceidle whitelist -" + mServicePackage; 139 String result = SystemUtil.runShellCommand(mInstrumentation, cmd); 140 } 141 addToWhitelist()142 public void addToWhitelist() throws IOException { 143 String cmd = "cmd deviceidle whitelist +" + mServicePackage; 144 String result = SystemUtil.runShellCommand(mInstrumentation, cmd); 145 } 146 tempWhitelist(long duration)147 public void tempWhitelist(long duration) throws IOException { 148 String cmd = "cmd deviceidle tempwhitelist -d " + duration + " " + mServicePackage; 149 String result = SystemUtil.runShellCommand(mInstrumentation, cmd); 150 } 151 removeFromTempWhitelist()152 public void removeFromTempWhitelist() throws IOException { 153 String cmd = "cmd deviceidle tempwhitelist -r " + mServicePackage; 154 SystemUtil.runShellCommand(mInstrumentation, cmd); 155 } 156 setAppOpMode(String opStr, String mode)157 public void setAppOpMode(String opStr, String mode) throws IOException { 158 String cmd = "cmd appops set " + mServicePackage + " " + opStr + " " + mode; 159 SystemUtil.runShellCommand(mInstrumentation, cmd); 160 } 161 cleanup()162 public void cleanup() throws IOException { 163 removeFromWhitelist(); 164 allowBackgroundOp(); 165 allowAnyInBackgroundOp(); 166 mUidWatcher.finish(); 167 mUidGoneListener.unregister(); 168 mUidForegroundListener.unregister(); 169 mData.recycle(); 170 } 171 getConnection(int index)172 public ServiceConnectionHandler getConnection(int index) { 173 return mConnections[index]; 174 } 175 getUid()176 public int getUid() { 177 return mUid; 178 } 179 getUidForegroundListener()180 public UidImportanceListener getUidForegroundListener() { 181 return mUidForegroundListener; 182 } 183 getUidGoneListener()184 public UidImportanceListener getUidGoneListener() { 185 return mUidGoneListener; 186 } 187 getUidWatcher()188 public WatchUidRunner getUidWatcher() { 189 return mUidWatcher; 190 } 191 ensureProcessGone()192 public void ensureProcessGone() { 193 ensureProcessGone(mDefaultWaitTime); 194 } 195 ensureProcessGone(long timeout)196 public void ensureProcessGone(long timeout) { 197 for (int i=0; i<mConnections.length; i++) { 198 mConnections[i].bind(timeout); 199 } 200 201 for (int i=0; i<mConnections.length; i++) { 202 IBinder serviceBinder = mConnections[i].getServiceIBinder(); 203 mConnections[i].unbind(timeout); 204 try { 205 serviceBinder.transact(IBinder.FIRST_CALL_TRANSACTION, mData, null, 0); 206 } catch (RemoteException e) { 207 } 208 } 209 210 // Wait for uid's process to go away. 211 mUidGoneListener.waitForValue(ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE, 212 ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE, timeout); 213 int importance = mAm.getPackageImportance(mServicePackage); 214 if (importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE) { 215 throw new IllegalStateException("Unexpected importance after killing process: " 216 + importance); 217 } 218 mUidWatcher.waitFor(WatchUidRunner.CMD_GONE, null, timeout); 219 } 220 } 221