1 /* 2 * Copyright (C) 2023 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 android.app.cts.getbindinguidimportance; 17 18 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; 19 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; 20 import static android.app.stubs.shared.Shared_getBindingUidImportance.ACTION_TEST_PROVIDER; 21 import static android.app.stubs.shared.Shared_getBindingUidImportance.ACTION_TEST_SERVICE_BINDING; 22 23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertNotEquals; 25 import static org.junit.Assert.assertTrue; 26 import static org.junit.Assert.fail; 27 28 import android.app.ActivityManager; 29 import android.app.Flags; 30 import android.app.Service; 31 import android.content.BroadcastReceiver; 32 import android.content.ComponentName; 33 import android.content.ContentProvider; 34 import android.content.ContentValues; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.database.Cursor; 38 import android.database.MatrixCursor; 39 import android.net.Uri; 40 import android.os.Binder; 41 import android.os.Handler; 42 import android.os.IBinder; 43 import android.os.Looper; 44 import android.os.Process; 45 import android.platform.test.annotations.RequiresFlagsEnabled; 46 import android.platform.test.flag.junit.CheckFlagsRule; 47 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 48 import android.util.Log; 49 50 import androidx.test.ext.junit.runners.AndroidJUnit4; 51 import androidx.test.platform.app.InstrumentationRegistry; 52 53 import com.android.compatibility.common.util.ShellIdentityUtils; 54 import com.android.compatibility.common.util.ShellUtils; 55 import com.android.compatibility.common.util.TestUtils; 56 57 import org.junit.Before; 58 import org.junit.BeforeClass; 59 import org.junit.Rule; 60 import org.junit.Test; 61 import org.junit.runner.RunWith; 62 63 import java.util.concurrent.CountDownLatch; 64 import java.util.concurrent.TimeUnit; 65 66 @RunWith(AndroidJUnit4.class) 67 public class ActivityManager_getBindingUidImportanceTest { 68 private static final String TAG = "ActivityManager_getBindingUidImportanceTest"; 69 70 @Rule 71 public final CheckFlagsRule mCheckFlagsRule = 72 DeviceFlagsValueProvider.createCheckFlagsRule(); 73 74 private static final String HELPER_PACKAGE = "android.app.stubs"; 75 private static final ComponentName HELPER_RECEIVER = new ComponentName( 76 HELPER_PACKAGE, "android.app.stubs.Receiver_getBindingUidImportance"); 77 78 private static final int RECEIVER_TIMEOUT_SEC = 60 * 3; 79 80 private static final int MY_UID = Process.myUid(); 81 private static final int NONEXISTENT_UID = -1; 82 private static int sHelperUid; 83 84 private static Context sContext; 85 86 private static int sLastUidImportance; 87 resetLastImportance()88 private static void resetLastImportance() { 89 sLastUidImportance = -1; 90 } 91 92 @BeforeClass beforeClass()93 public static void beforeClass() throws Exception { 94 sContext = InstrumentationRegistry.getInstrumentation().getContext(); 95 96 sHelperUid = sContext.getPackageManager().getPackageUid(HELPER_PACKAGE, 0); 97 98 assertNotEquals("Helper UID must be different from mine", sHelperUid, MY_UID); 99 Log.d(TAG, "Helper UID: " + sHelperUid); 100 } 101 102 @Before setUp()103 public void setUp() { 104 // Force-stop the helper app to make sure there's no leftover binding, etc. 105 ShellUtils.runShellCommand("am force-stop %s", HELPER_PACKAGE); 106 107 resetLastImportance(); 108 } 109 110 /** 111 * Test: get the importance of an UID that's binding to this process. 112 * 113 * The API should return the actual importance. 114 */ 115 // Add the flag annotation 116 @Test 117 @RequiresFlagsEnabled(Flags.FLAG_GET_BINDING_UID_IMPORTANCE) testWithServiceBinding()118 public void testWithServiceBinding() throws Exception { 119 sendBroadcastAndWait(ACTION_TEST_SERVICE_BINDING); 120 121 // Because we call getBindingUidImportance() when the UID in running a receiver, 122 // the importance shouldn't be cached. 123 assertImportanceNotCached(sLastUidImportance); 124 125 // Now the binding is disconnected, it should return GONE. 126 resetLastImportance(); 127 assertImportanceGone(getBindingUidImportance(sContext, sHelperUid)); 128 } 129 130 /** 131 * Test: get the importance of an UID that's accessing a provider in this process. 132 * 133 * The API should return the actual importance. 134 */ 135 // Add the flag annotation 136 @Test 137 @RequiresFlagsEnabled(Flags.FLAG_GET_BINDING_UID_IMPORTANCE) testWithProviderAccess()138 public void testWithProviderAccess() throws Exception { 139 sendBroadcastAndWait(ACTION_TEST_PROVIDER); 140 141 // Because we call getBindingUidImportance() when the UID in running a receiver, 142 // the importance shouldn't be cached. 143 assertImportanceNotCached(sLastUidImportance); 144 145 // Now the provider client is closed, it should return GONE. 146 // But the provider connection isn't disconnected right away; there's some timeout, 147 // so we account for that with waitUntil. 148 resetLastImportance(); 149 TestUtils.waitUntil("UID importance should become GONE", 60, () -> { 150 return getBindingUidImportance(sContext, sHelperUid) == IMPORTANCE_GONE; 151 }); 152 } 153 154 /** 155 * Test: try to get the importance of an UID that's not binding and not accessing the provider. 156 * It should return GONE. 157 */ 158 // Add the flag annotation 159 @Test 160 @RequiresFlagsEnabled(Flags.FLAG_GET_BINDING_UID_IMPORTANCE) testNoBindingNoProviderAccess()161 public void testNoBindingNoProviderAccess() { 162 assertImportanceGone(getBindingUidImportance(sContext, sHelperUid)); 163 } 164 165 /** 166 * Test: try to get the importance of an UID that doesn't exist. 167 * It should return GONE. 168 */ 169 // Add the flag annotation 170 @Test 171 @RequiresFlagsEnabled(Flags.FLAG_GET_BINDING_UID_IMPORTANCE) testNonExistingUid()172 public void testNonExistingUid() { 173 assertImportanceGone(getBindingUidImportance(sContext, NONEXISTENT_UID)); 174 } 175 176 /** 177 * Getting the importance of own UID is always allowed. 178 */ 179 // Add the flag annotation 180 @Test 181 @RequiresFlagsEnabled(Flags.FLAG_GET_BINDING_UID_IMPORTANCE) testSelfImportance()182 public void testSelfImportance() { 183 assertImportanceNotCached(getBindingUidImportance(sContext, MY_UID)); 184 } 185 assertImportanceNotCached(int importance)186 private static void assertImportanceNotCached(int importance) { 187 if (importance < 0) { 188 fail("importance is negative. getBindingUidImportance() wasn't called?"); 189 } 190 if (importance > IMPORTANCE_SERVICE) { 191 fail("Importance should be non cached, but was " + importance); 192 } 193 } 194 assertImportanceGone(int importance)195 public static void assertImportanceGone(int importance) { 196 assertEquals("Importance should seem to be GONE", importance, IMPORTANCE_GONE); 197 } 198 199 /** 200 * Call ActivityManager.getBindingUidImportance() with the required permission, and 201 * return the result. It also updates {@link #sLastUidImportance}. 202 * @return the importance 203 */ getBindingUidImportance(Context context, int uid)204 private static int getBindingUidImportance(Context context, int uid) { 205 sLastUidImportance = ShellIdentityUtils.invokeMethodWithShellPermissions( 206 context.getSystemService(ActivityManager.class), 207 (am) -> am.getBindingUidImportance(uid), 208 android.Manifest.permission.GET_BINDING_UID_IMPORTANCE); 209 Log.d(TAG, "Importance of UID " + uid + " is " + sLastUidImportance); 210 return sLastUidImportance; 211 } 212 sendBroadcastAndWait(String action)213 private void sendBroadcastAndWait(String action) throws Exception { 214 final CountDownLatch latch = new CountDownLatch(1); 215 216 final BroadcastReceiver resultReceiver = new BroadcastReceiver() { 217 @Override 218 public void onReceive(Context context, Intent intent) { 219 Log.d(TAG, "Result received"); 220 latch.countDown(); 221 } 222 }; 223 224 sContext.sendOrderedBroadcast( 225 new Intent(action).setComponent(HELPER_RECEIVER), 226 null, // receiverPermission 227 resultReceiver, 228 new Handler(Looper.getMainLooper()), // scheduler 229 0, // initialCode 230 null, // initialData 231 null); // initialExtras 232 233 assertTrue("Receiver didn't finish in time", 234 latch.await(RECEIVER_TIMEOUT_SEC, TimeUnit.SECONDS)); 235 } 236 237 public static class MyService extends Service { 238 @Override onBind(Intent intent)239 public IBinder onBind(Intent intent) { 240 Log.d(TAG, "MyService.onBind"); 241 242 // Update sLastUidImportance. 243 getBindingUidImportance(sContext, sHelperUid); 244 return new Binder(); 245 } 246 } 247 248 public static class MyProvider extends ContentProvider { 249 @Override onCreate()250 public boolean onCreate() { 251 return true; 252 } 253 254 @Override query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)255 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 256 String sortOrder) { 257 Log.d(TAG, "MyProvider.query"); 258 259 // Update sLastUidImportance. 260 getBindingUidImportance(sContext, sHelperUid); 261 262 // Return a non-null cursor. 263 return new MatrixCursor(new String[]{"xxx"}, 0); 264 } 265 266 @Override getType(Uri uri)267 public String getType(Uri uri) { 268 return null; 269 } 270 271 @Override insert(Uri uri, ContentValues values)272 public Uri insert(Uri uri, ContentValues values) { 273 return null; 274 } 275 276 @Override delete(Uri uri, String selection, String[] selectionArgs)277 public int delete(Uri uri, String selection, String[] selectionArgs) { 278 return 0; 279 } 280 281 @Override update(Uri uri, ContentValues values, String selection, String[] selectionArgs)282 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 283 return 0; 284 } 285 } 286 } 287