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