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