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