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.test.suitebuilder.annotation.MediumTest; 25 import android.util.Log; 26 27 import java.io.File; 28 import java.io.IOException; 29 30 /** 31 * Test whether Binder calls inherit thread priorities correctly. 32 */ 33 public 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