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