• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 
22 import android.app.ActivityManager;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.ServiceConnection;
27 import android.platform.test.annotations.IgnoreUnderRavenwood;
28 import android.platform.test.ravenwood.RavenwoodRule;
29 import android.util.Log;
30 
31 import androidx.test.InstrumentationRegistry;
32 import androidx.test.ext.junit.runners.AndroidJUnit4;
33 
34 import org.junit.After;
35 import org.junit.Before;
36 import org.junit.Rule;
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 
40 import java.io.File;
41 import java.io.IOException;
42 
43 /**
44  * Test whether Binder calls inherit thread priorities correctly.
45  */
46 @RunWith(AndroidJUnit4.class)
47 @IgnoreUnderRavenwood(blockedBy = ActivityManager.class)
48 public class BinderThreadPriorityTest {
49     private static final String TAG = "BinderThreadPriorityTest";
50 
51     @Rule
52     public final RavenwoodRule mRavenwood = new RavenwoodRule();
53 
54     private Context mContext;
55     private IBinderThreadPriorityService mService;
56     private int mSavedPriority;
57 
58     private ServiceConnection mConnection = new ServiceConnection() {
59         public void onServiceConnected(ComponentName name, IBinder service) {
60             synchronized (BinderThreadPriorityTest.this) {
61                 mService = IBinderThreadPriorityService.Stub.asInterface(service);
62                 BinderThreadPriorityTest.this.notifyAll();
63             }
64         }
65 
66         public void onServiceDisconnected(ComponentName name) {
67             mService = null;
68         }
69     };
70 
71     private static class ServiceStub extends IBinderThreadPriorityService.Stub {
getThreadPriority()72         public int getThreadPriority() { fail(); return -999; }
getThreadSchedulerGroup()73         public String getThreadSchedulerGroup() { fail(); return null; }
setPriorityAndCallBack(int p, IBinderThreadPriorityService cb)74         public void setPriorityAndCallBack(int p, IBinderThreadPriorityService cb) { fail(); }
callBack(IBinderThreadPriorityService cb)75         public void callBack(IBinderThreadPriorityService cb) { fail(); }
fail()76         private static void fail() { throw new RuntimeException("unimplemented"); }
77     }
78 
79     @Before
setUp()80     public void setUp() throws Exception {
81         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
82         mContext.bindService(
83                 new Intent(mContext, BinderThreadPriorityService.class),
84                 mConnection, Context.BIND_AUTO_CREATE);
85 
86         synchronized (this) {
87             if (mService == null) {
88                 try {
89                     wait(30000);
90                 } catch (InterruptedException e) {
91                     throw new RuntimeException(e);
92                 }
93                 assertNotNull("Gave up waiting for BinderThreadPriorityService", mService);
94             }
95         }
96 
97         mSavedPriority = Process.getThreadPriority(Process.myTid());
98         Process.setThreadPriority(mSavedPriority);  // To realign priority & cgroup, if needed
99         assertEquals(expectedSchedulerGroup(mSavedPriority), getSchedulerGroup());
100         Log.i(TAG, "Saved priority: " + mSavedPriority);
101     }
102 
103     @After
tearDown()104     public void tearDown() throws Exception {
105         // HACK -- see bug 2665914 -- setThreadPriority() doesn't always set the
106         // scheduler group reliably unless we start out with background priority.
107         Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
108         Process.setThreadPriority(mSavedPriority);
109         assertEquals(mSavedPriority, Process.getThreadPriority(Process.myTid()));
110         assertEquals(expectedSchedulerGroup(mSavedPriority), getSchedulerGroup());
111 
112         mContext.unbindService(mConnection);
113     }
114 
getSchedulerGroup()115     public static String getSchedulerGroup() {
116         String fn = "/proc/" + Process.myPid() + "/task/" + Process.myTid() + "/cgroup";
117         try {
118             String cgroup = FileUtils.readTextFile(new File(fn), 1024, null);
119             for (String line : cgroup.split("\n")) {
120                 String fields[] = line.trim().split(":");
121                     if (fields.length == 3 && fields[1].equals("cpu")) return fields[2];
122             }
123         } catch (IOException e) {
124             Log.e(TAG, "Can't read: " + fn, e);
125         }
126         return null;  // Unknown
127     }
128 
expectedSchedulerGroup(int prio)129     public static String expectedSchedulerGroup(int prio) {
130         return "/";
131     }
132 
133     @Test
testPassPriorityToService()134     public void testPassPriorityToService() throws Exception {
135         for (int prio = 19; prio >= -20; prio--) {
136             Process.setThreadPriority(prio);
137 
138             // Local
139             assertEquals(prio, Process.getThreadPriority(Process.myTid()));
140             assertEquals(expectedSchedulerGroup(prio), getSchedulerGroup());
141 
142             // Remote
143             assertEquals(prio, mService.getThreadPriority());
144             assertEquals(expectedSchedulerGroup(prio), mService.getThreadSchedulerGroup());
145         }
146     }
147 
148     @Test
testCallBackFromServiceWithPriority()149     public void testCallBackFromServiceWithPriority() throws Exception {
150         for (int prio = -20; prio <= 19; prio++) {
151             final int expected = prio;
152             mService.setPriorityAndCallBack(prio, new ServiceStub() {
153                 public void callBack(IBinderThreadPriorityService cb) {
154                     assertEquals(expected, Process.getThreadPriority(Process.myTid()));
155                     assertEquals(expectedSchedulerGroup(expected), getSchedulerGroup());
156                 }
157             });
158 
159             assertEquals(mSavedPriority, Process.getThreadPriority(Process.myTid()));
160 
161             // BROKEN -- see bug 2665954 -- scheduler group doesn't get reset
162             // properly after a back-call with a different priority.
163             // assertEquals(expectedSchedulerGroup(mSavedPriority), getSchedulerGroup());
164         }
165     }
166 }
167