1 /* 2 * Copyright (C) 2008 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.os.cts; 18 19 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertFalse; 23 import static org.junit.Assert.assertNotEquals; 24 import static org.junit.Assert.assertNull; 25 import static org.junit.Assert.assertThrows; 26 import static org.junit.Assert.assertTrue; 27 import static org.junit.Assert.fail; 28 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.ServiceConnection; 33 import android.content.pm.PackageManager; 34 import android.os.IBinder; 35 import android.os.Process; 36 import android.platform.test.annotations.AppModeNonSdkSandbox; 37 import android.platform.test.annotations.AppModeSdkSandbox; 38 import android.platform.test.annotations.IgnoreUnderRavenwood; 39 import android.platform.test.annotations.RequiresFlagsEnabled; 40 import android.platform.test.flag.junit.CheckFlagsRule; 41 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 42 import android.platform.test.flag.junit.RavenwoodFlagsValueProvider; 43 import android.platform.test.ravenwood.RavenwoodRule; 44 import android.util.Log; 45 46 import androidx.test.InstrumentationRegistry; 47 import androidx.test.runner.AndroidJUnit4; 48 49 import com.android.sdksandbox.flags.Flags; 50 51 import org.junit.After; 52 import org.junit.Before; 53 import org.junit.Rule; 54 import org.junit.Test; 55 import org.junit.runner.RunWith; 56 57 /** 58 * CTS for {@link Process}. 59 * 60 * We have more test in cts/tests/process/ too. 61 */ 62 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).") 63 @RunWith(AndroidJUnit4.class) 64 public class ProcessTest { 65 @Rule public RavenwoodRule mRavenwood = new RavenwoodRule(); 66 67 // Required for RequiresFlagsEnabled and RequiresFlagsDisabled annotations to take effect. 68 @Rule 69 public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isOnRavenwood() 70 ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule() 71 : DeviceFlagsValueProvider.createCheckFlagsRule(); 72 73 public static final int THREAD_PRIORITY_HIGHEST = -20; 74 private static final String NONE_EXISITENT_NAME = "abcdefcg"; 75 private static final String WRONG_CACHE_NAME = "cache_abcdefg"; 76 private static final String PROCESS_SHELL= "shell"; 77 private static final String PROCESS_CACHE= "cache"; 78 private static final String REMOTE_SERVICE = "android.app.REMOTESERVICE"; 79 private static final int APP_UID = 10001; 80 private static final int FIRST_SDK_SANDBOX_UID = 20000; 81 private static final int LAST_SDK_SANDBOX_UID = 29999; 82 private static final int SANDBOX_SDK_UID = 20001; 83 private static final int ISOLATED_PROCESS_UID = 99037; 84 private static final int APP_ZYGOTE_ISOLATED_UID = 90123; 85 private static final String TAG = "ProcessTest"; 86 private ISecondary mSecondaryService = null; 87 private Intent mIntent; 88 private Object mSync; 89 private boolean mHasConnected; 90 private boolean mHasDisconnected; 91 private ServiceConnection mSecondaryConnection; 92 private Context mContext; 93 94 @Before setUp()95 public void setUp() throws Exception { 96 if (mRavenwood.isUnderRavenwood()) return; 97 mContext = InstrumentationRegistry.getContext(); 98 mSync = new Object(); 99 mSecondaryConnection = new ServiceConnection() { 100 public void onServiceConnected(ComponentName className, 101 IBinder service) { 102 // Connecting to a secondary interface is the same as any 103 // other interface. 104 android.util.Log.d(TAG, "connected"); 105 mSecondaryService = ISecondary.Stub.asInterface(service); 106 synchronized (mSync) { 107 mHasConnected = true; 108 mSync.notify(); 109 } 110 } 111 public void onServiceDisconnected(ComponentName className) { 112 Log.d(TAG, "disconnected"); 113 mSecondaryService = null; 114 synchronized (mSync) { 115 mHasDisconnected = true; 116 mSync.notify(); 117 } 118 } 119 }; 120 mIntent = new Intent(REMOTE_SERVICE); 121 mIntent.setPackage(mContext.getPackageName()); 122 mContext.startService(mIntent); 123 124 Intent secondaryIntent = new Intent(ISecondary.class.getName()); 125 secondaryIntent.setPackage(mContext.getPackageName()); 126 mContext.bindService(secondaryIntent, mSecondaryConnection, 127 Context.BIND_AUTO_CREATE); 128 synchronized (mSync) { 129 if (!mHasConnected) { 130 try { 131 mSync.wait(); 132 } catch (InterruptedException e) { 133 } 134 } 135 } 136 } 137 138 @After tearDown()139 public void tearDown() throws Exception { 140 if (mRavenwood.isUnderRavenwood()) return; 141 if (mIntent != null) { 142 mContext.stopService(mIntent); 143 } 144 if (mSecondaryConnection != null) { 145 mContext.unbindService(mSecondaryConnection); 146 } 147 } 148 149 @Test 150 @IgnoreUnderRavenwood(reason = "Requires kernel support") testMiscMethods()151 public void testMiscMethods() { 152 /* 153 * Test setThreadPriority(int) and setThreadPriority(int, int) 154 * 1.Set the priority of the calling thread, based on Linux priorities level, 155 * from -20 for highest scheduling priority to 19 for lowest scheduling priority. 156 * 2.Throws IllegalArgumentException if tid does not exist. 157 */ 158 int myTid = Process.myTid(); 159 160 int priority = Process.getThreadPriority(myTid); 161 assertTrue(priority >= THREAD_PRIORITY_HIGHEST 162 && priority <= Process.THREAD_PRIORITY_LOWEST); 163 164 Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO); 165 assertEquals(Process.THREAD_PRIORITY_AUDIO, Process.getThreadPriority(myTid)); 166 167 Process.setThreadPriority(myTid, Process.THREAD_PRIORITY_LOWEST); 168 assertEquals(Process.THREAD_PRIORITY_LOWEST, Process.getThreadPriority(myTid)); 169 170 Process.setThreadPriority(myTid, THREAD_PRIORITY_HIGHEST); 171 assertEquals(THREAD_PRIORITY_HIGHEST, Process.getThreadPriority(myTid)); 172 173 int invalidPriority = THREAD_PRIORITY_HIGHEST - 1; 174 Process.setThreadPriority(myTid, invalidPriority); 175 assertEquals(THREAD_PRIORITY_HIGHEST, Process.getThreadPriority(myTid)); 176 177 try { 178 Process.setThreadPriority(-1, Process.THREAD_PRIORITY_DEFAULT); 179 fail("Should throw IllegalArgumentException"); 180 } catch (IllegalArgumentException e) { 181 // expect 182 } // Hard to address logic of throws SecurityException 183 184 /* 185 * Returns the UID assigned to a particular user name, or -1 if there is 186 * none. If the given string consists of only numbers, it is converted 187 * directly to a uid. 188 */ 189 assertTrue(Process.getUidForName(PROCESS_SHELL) > 0); 190 assertEquals(-1, Process.getUidForName(NONE_EXISITENT_NAME)); 191 assertEquals(0, Process.getUidForName("0")); 192 193 /* 194 * Returns the GID assigned to a particular user name, or -1 if there is 195 * none. If the given string consists of only numbers, it is converted 196 * directly to a gid. 197 */ 198 assertTrue(Process.getGidForName(PROCESS_CACHE) > 0); 199 assertEquals(-1, Process.getGidForName(WRONG_CACHE_NAME)); 200 assertEquals(0, Process.getGidForName("0")); 201 202 assertTrue(Process.myUid() >= 0); 203 204 assertNotEquals(null, Process.getExclusiveCores()); 205 } 206 207 /** 208 * Test point of killProcess(int) 209 * Only the process running the caller's packages/application 210 * and any additional processes created by that app be able to kill each other's processes. 211 */ 212 @Test 213 @IgnoreUnderRavenwood(reason = "Requires kernel support") testKillProcess()214 public void testKillProcess() throws Exception { 215 long time = 0; 216 int servicePid = 0; 217 try { 218 servicePid = mSecondaryService.getPid(); 219 time = mSecondaryService.getElapsedCpuTime(); 220 } finally { 221 mContext.stopService(mIntent); 222 mIntent = null; 223 } 224 225 assertTrue(time > 0); 226 assertTrue(servicePid != Process.myPid()); 227 228 Process.killProcess(servicePid); 229 synchronized (mSync) { 230 if (!mHasDisconnected) { 231 try { 232 mSync.wait(); 233 } catch (InterruptedException e) { 234 } 235 } 236 } 237 assertTrue(mHasDisconnected); 238 } 239 240 /** 241 * Test myPid() point. 242 * Returns the identifier of this process, which can be used with 243 * {@link #killProcess} and {@link #sendSignal}. 244 * Test sendSignal(int) point. 245 * Send a signal to the given process. 246 */ 247 @Test 248 @IgnoreUnderRavenwood(reason = "Requires kernel support") testSendSignal()249 public void testSendSignal() throws Exception { 250 int servicePid = 0; 251 try { 252 servicePid = mSecondaryService.getPid(); 253 } finally { 254 mContext.stopService(mIntent); 255 mIntent = null; 256 } 257 assertTrue(servicePid != 0); 258 assertTrue(Process.myPid() != servicePid); 259 Process.sendSignal(servicePid, Process.SIGNAL_KILL); 260 synchronized (mSync) { 261 if (!mHasDisconnected) { 262 try { 263 mSync.wait(); 264 } catch (InterruptedException e) { 265 } 266 } 267 } 268 assertTrue(mHasDisconnected); 269 } 270 271 /** 272 * Tests {@link Process#isSdkSandbox() (boolean)} API. 273 */ 274 @Test 275 @AppModeNonSdkSandbox testIsSdkSandbox()276 public void testIsSdkSandbox() { 277 assertFalse(Process.isSdkSandbox()); 278 } 279 280 /** 281 * Tests for {@link Process#isSdkSandboxUid() (boolean)} API. 282 */ 283 @Test testIsSdkSandboxUid_UidNotSandboxUid()284 public void testIsSdkSandboxUid_UidNotSandboxUid() { 285 assertFalse(Process.isSdkSandboxUid(APP_UID)); 286 } 287 288 /** 289 * Tests for the following APIs 290 * {@link Process#isSdkSandboxUid() (boolean)} 291 */ 292 @Test testSdkSandboxUids()293 public void testSdkSandboxUids() { 294 for (int i = FIRST_SDK_SANDBOX_UID; i <= LAST_SDK_SANDBOX_UID; i++) { 295 assertTrue(Process.isSdkSandboxUid(i)); 296 } 297 } 298 299 /** 300 * Tests for {@link Process#getAppUidForSdkSandboxUid(int) (int)} API. 301 */ 302 @Test testGetAppUidForSdkSandboxUid()303 public void testGetAppUidForSdkSandboxUid() { 304 assertEquals(APP_UID, Process.getAppUidForSdkSandboxUid(SANDBOX_SDK_UID)); 305 } 306 307 @Test testGetAppUidForSdkSandboxUid_invalidInput()308 public void testGetAppUidForSdkSandboxUid_invalidInput() { 309 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 310 () -> Process.getAppUidForSdkSandboxUid(-1)); 311 assertEquals(exception.getMessage(), "Input UID is not an SDK sandbox UID"); 312 } 313 314 /** 315 * Tests for {@link Process#getSdkSandboxUidForAppUid(int) (int)} API 316 */ 317 @Test 318 @RequiresFlagsEnabled(Flags.FLAG_SDK_SANDBOX_UID_TO_APP_UID_API) testGetSdkSandboxUidForAppUid()319 public void testGetSdkSandboxUidForAppUid() { 320 assertEquals(SANDBOX_SDK_UID, Process.getSdkSandboxUidForAppUid(APP_UID)); 321 } 322 323 @Test 324 @RequiresFlagsEnabled(Flags.FLAG_SDK_SANDBOX_UID_TO_APP_UID_API) testGetSdkSandboxUidForAppUid_invalidInput()325 public void testGetSdkSandboxUidForAppUid_invalidInput() { 326 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 327 () -> Process.getSdkSandboxUidForAppUid(-1)); 328 assertEquals(exception.getMessage(), "Input UID is not an app UID"); 329 } 330 331 332 /** 333 * Tests that the reserved UID is not taken by an actual package. 334 */ 335 @Test 336 @IgnoreUnderRavenwood(blockedBy = PackageManager.class) testReservedVirtualUid()337 public void testReservedVirtualUid() { 338 PackageManager pm = mContext.getPackageManager(); 339 final String name = pm.getNameForUid(Process.SDK_SANDBOX_VIRTUAL_UID); 340 assertNull(name); 341 342 // PackageManager#getPackagesForUid requires android.permission.INTERACT_ACROSS_USERS for 343 // cross-user calls. 344 runWithShellPermissionIdentity(() -> { 345 final String[] packages = pm.getPackagesForUid(Process.SDK_SANDBOX_VIRTUAL_UID); 346 assertNull(packages); 347 }); 348 } 349 350 /** 351 * Tests for {@link Process#isIsolatedUid(int)} (int)} API. 352 */ 353 @Test testIsolatedProccesUids()354 public void testIsolatedProccesUids() { 355 assertTrue(Process.isIsolatedUid(ISOLATED_PROCESS_UID)); 356 assertTrue(Process.isIsolatedUid(APP_ZYGOTE_ISOLATED_UID)); 357 // A random UID before the FIRST_APPLICATION_UID is not an isolated process uid. 358 assertFalse(Process.isIsolatedUid(57)); 359 // Sdk Sandbox UID is not an isolated process uid 360 assertFalse(Process.isIsolatedUid(SANDBOX_SDK_UID)); 361 // App uid is not an isolated process uid 362 assertFalse(Process.isIsolatedUid(APP_UID)); 363 } 364 365 @Test testApplicationUids()366 public void testApplicationUids() { 367 assertTrue(Process.isApplicationUid(Process.FIRST_APPLICATION_UID)); 368 assertTrue(Process.isApplicationUid(Process.LAST_APPLICATION_UID)); 369 assertFalse(Process.isApplicationUid(Process.ROOT_UID)); 370 assertFalse(Process.isApplicationUid(Process.PHONE_UID)); 371 assertFalse(Process.isApplicationUid(Process.INVALID_UID)); 372 } 373 374 @Test testIs64Bit()375 public void testIs64Bit() { 376 // We're not concerned with the answer, just that it works 377 Process.is64Bit(); 378 } 379 } 380