1 /* 2 * Copyright (C) 2023 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.adpf.atom.app; 18 19 import static android.adpf.atom.common.ADPFAtomTestConstants.ACTION_CREATE_DEAD_TIDS_THEN_GO_BACKGROUND; 20 import static android.adpf.atom.common.ADPFAtomTestConstants.ACTION_CREATE_REGULAR_HINT_SESSIONS; 21 import static android.adpf.atom.common.ADPFAtomTestConstants.CONTENT_KEY_RESULT_TIDS; 22 import static android.adpf.atom.common.ADPFAtomTestConstants.CONTENT_KEY_UID; 23 import static android.adpf.atom.common.ADPFAtomTestConstants.CONTENT_URI_STRING; 24 import static android.adpf.atom.common.ADPFAtomTestConstants.INTENT_ACTION_KEY; 25 26 import static org.junit.Assert.assertNotNull; 27 import static org.junit.Assume.assumeNotNull; 28 29 import android.app.Activity; 30 import android.content.ContentValues; 31 import android.content.Intent; 32 import android.net.Uri; 33 import android.os.Build; 34 import android.os.Bundle; 35 import android.os.PerformanceHintManager; 36 import android.os.Process; 37 import android.util.ArrayMap; 38 import android.util.Log; 39 40 import com.android.compatibility.common.util.PropertyUtil; 41 42 import java.util.Map; 43 import java.util.StringJoiner; 44 import java.util.concurrent.CountDownLatch; 45 import java.util.concurrent.atomic.AtomicInteger; 46 47 /** An activity which performs ADPF actions. */ 48 public class ADPFAtomTestActivity extends Activity { 49 private static final String TAG = ADPFAtomTestActivity.class.getSimpleName(); 50 51 52 private final Map<String, Bundle> mResult = new ArrayMap<>(); 53 54 private static final int FIRST_API_LEVEL = PropertyUtil.getFirstApiLevel(); 55 56 @Override onCreate(Bundle bundle)57 public void onCreate(Bundle bundle) { 58 super.onCreate(bundle); 59 60 final Intent intent = this.getIntent(); 61 assertNotNull(intent); 62 final String action = intent.getStringExtra(INTENT_ACTION_KEY); 63 assertNotNull(action); 64 switch (action) { 65 case ACTION_CREATE_DEAD_TIDS_THEN_GO_BACKGROUND: 66 try { 67 final int[] tids = createHintSessionWithExitedThreads(); 68 final StringJoiner sb = new StringJoiner(","); 69 for (int tid : tids) { 70 sb.add(String.valueOf(tid)); 71 } 72 ContentValues values = new ContentValues(); 73 values.put(CONTENT_KEY_RESULT_TIDS, sb.toString()); 74 values.put(CONTENT_KEY_UID, String.valueOf(Process.myUid())); 75 assertNotNull( 76 getContentResolver().insert(Uri.parse(CONTENT_URI_STRING), values)); 77 } catch (InterruptedException e) { 78 throw new RuntimeException(e); 79 } 80 moveTaskToBack(true); 81 Log.i(TAG, "Moved task ADPFHintSessionDeviceActivity to back"); 82 break; 83 case ACTION_CREATE_REGULAR_HINT_SESSIONS: 84 PerformanceHintManager.Session session = createPerformanceHintSession(); 85 if (FIRST_API_LEVEL < Build.VERSION_CODES.S) { 86 assumeNotNull(session); 87 } else { 88 assertNotNull(session); 89 } 90 break; 91 } 92 } 93 94 /** 95 * Read the run result of a specific action 96 */ getRunResult(String actionKey)97 public Bundle getRunResult(String actionKey) { 98 synchronized (mResult) { 99 return mResult.get(actionKey); 100 } 101 } 102 createHintSessionWithExitedThreads()103 private int[] createHintSessionWithExitedThreads() throws InterruptedException { 104 PerformanceHintManager hintManager = getApplicationContext().getSystemService( 105 PerformanceHintManager.class); 106 assertNotNull(hintManager); 107 CountDownLatch stopLatch = new CountDownLatch(1); 108 int[] tids = createThreads(5, stopLatch); 109 hintManager.createHintSession(tids, 100); 110 stopLatch.countDown(); 111 return tids; 112 } 113 createThreads(int tidCnt, CountDownLatch stopLatch)114 private int[] createThreads(int tidCnt, CountDownLatch stopLatch) throws InterruptedException { 115 int[] tids = new int[tidCnt]; 116 CountDownLatch latch = new CountDownLatch(tidCnt); 117 AtomicInteger k = new AtomicInteger(0); 118 for (int i = 0; i < tidCnt; i++) { 119 final Thread t = new Thread(() -> { 120 tids[k.getAndIncrement()] = android.os.Process.myTid(); 121 try { 122 latch.countDown(); 123 stopLatch.await(); 124 } catch (InterruptedException e) { 125 throw new RuntimeException(e); 126 } 127 }); 128 t.start(); 129 } 130 latch.await(); 131 return tids; 132 } 133 createPerformanceHintSession()134 private PerformanceHintManager.Session createPerformanceHintSession() { 135 final long testTargetDuration = 12345678L; 136 PerformanceHintManager hintManager = getApplicationContext().getSystemService( 137 PerformanceHintManager.class); 138 assertNotNull(hintManager); 139 return hintManager.createHintSession( 140 new int[]{android.os.Process.myTid()}, testTargetDuration); 141 } 142 } 143