1 /* 2 * Copyright (C) 2022 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 com.android.ondevicepersonalization.services; 18 19 import android.annotation.NonNull; 20 import android.os.Handler; 21 import android.os.Looper; 22 import android.os.Process; 23 import android.os.StrictMode; 24 import android.os.StrictMode.ThreadPolicy; 25 26 import com.google.common.util.concurrent.ListeningExecutorService; 27 import com.google.common.util.concurrent.ListeningScheduledExecutorService; 28 import com.google.common.util.concurrent.MoreExecutors; 29 import com.google.common.util.concurrent.ThreadFactoryBuilder; 30 31 import java.util.Optional; 32 import java.util.concurrent.Executors; 33 import java.util.concurrent.ThreadFactory; 34 35 /** 36 * All executors of the OnDevicePersonalization module. 37 */ 38 public final class OnDevicePersonalizationExecutors { 39 private static final ListeningExecutorService sHighPriorityBackgroundExecutor = 40 MoreExecutors.listeningDecorator( 41 Executors.newFixedThreadPool( 42 /* nThreads */ 2, 43 createThreadFactory( 44 "HPBG Thread", 45 Process.THREAD_PRIORITY_BACKGROUND 46 + Process.THREAD_PRIORITY_MORE_FAVORABLE, 47 Optional.of(getIoThreadPolicy())))); 48 49 private static final ListeningExecutorService sLowPriorityBackgroundExecutor = 50 MoreExecutors.listeningDecorator( 51 Executors.newFixedThreadPool( 52 /* nThreads */ 2, 53 createThreadFactory( 54 "LPBG Thread", 55 Process.THREAD_PRIORITY_BACKGROUND 56 + Process.THREAD_PRIORITY_LESS_FAVORABLE, 57 Optional.of(getIoThreadPolicy())))); 58 59 private static final ListeningExecutorService sBackgroundExecutor = 60 MoreExecutors.listeningDecorator(Executors.newFixedThreadPool( 61 /* nThreads */ 4, 62 createThreadFactory("BG Thread", Process.THREAD_PRIORITY_BACKGROUND, 63 Optional.of(getIoThreadPolicy())))); 64 65 private static final ListeningExecutorService sLightweightExecutor = 66 MoreExecutors.listeningDecorator(Executors.newFixedThreadPool( 67 /* nThreads */ Math.max(2, Runtime.getRuntime().availableProcessors() - 2), 68 createThreadFactory("Lite Thread", Process.THREAD_PRIORITY_DEFAULT, 69 Optional.of(getAsyncThreadPolicy())))); 70 71 private static final ListeningExecutorService sBlockingExecutor = 72 MoreExecutors.listeningDecorator(Executors.newCachedThreadPool( 73 createThreadFactory("Blocking Thread", Process.THREAD_PRIORITY_BACKGROUND 74 + Process.THREAD_PRIORITY_LESS_FAVORABLE, Optional.empty()))); 75 76 private static final ListeningScheduledExecutorService sScheduledExecutor = 77 MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool( 78 /* nThreads */ 4, 79 createThreadFactory("SCH Thread", Process.THREAD_PRIORITY_BACKGROUND, 80 Optional.of(getIoThreadPolicy())))); 81 82 private static final Handler sHandlerForMainThread = new Handler(Looper.getMainLooper()); 83 OnDevicePersonalizationExecutors()84 private OnDevicePersonalizationExecutors() { 85 } 86 87 88 /** 89 * Returns the higher priority BG executor. 90 */ 91 @NonNull getHighPriorityBackgroundExecutor()92 public static ListeningExecutorService getHighPriorityBackgroundExecutor() { 93 return sHighPriorityBackgroundExecutor; 94 } 95 96 97 /** 98 * Returns the lower priority BG executor. 99 */ 100 @NonNull getLowPriorityBackgroundExecutor()101 public static ListeningExecutorService getLowPriorityBackgroundExecutor() { 102 return sLowPriorityBackgroundExecutor; 103 } 104 105 /** 106 * Returns an executor suitable for long-running tasks, like database operations, file I/O, or 107 * heavy CPU-bound computation. 108 */ 109 @NonNull getBackgroundExecutor()110 public static ListeningExecutorService getBackgroundExecutor() { 111 return sBackgroundExecutor; 112 } 113 114 /** 115 * Returns an executor for tasks that don't do direct I/O and that are fast (<10ms). 116 */ 117 @NonNull getLightweightExecutor()118 public static ListeningExecutorService getLightweightExecutor() { 119 return sLightweightExecutor; 120 } 121 122 /** 123 * Returns an executor suitable for tasks which block for indeterminate amounts of time and 124 * are not CPU bound. 125 */ 126 @NonNull getBlockingExecutor()127 public static ListeningExecutorService getBlockingExecutor() { 128 return sBlockingExecutor; 129 } 130 131 /** 132 * Returns an executor that can start tasks after a delay. 133 */ 134 @NonNull getScheduledExecutor()135 public static ListeningScheduledExecutorService getScheduledExecutor() { 136 return sScheduledExecutor; 137 } 138 139 /** 140 * Returns a Handler for the main thread. 141 */ getHandlerForMainThread()142 public static Handler getHandlerForMainThread() { 143 return sHandlerForMainThread; 144 } 145 createThreadFactory( final String name, final int priority, final Optional<StrictMode.ThreadPolicy> policy)146 private static ThreadFactory createThreadFactory( 147 final String name, final int priority, final Optional<StrictMode.ThreadPolicy> policy) { 148 return new ThreadFactoryBuilder() 149 .setDaemon(true) 150 .setNameFormat(name + " #%d") 151 .setThreadFactory( 152 new ThreadFactory() { 153 @Override 154 public Thread newThread(final Runnable runnable) { 155 return new Thread(new Runnable() { 156 @Override 157 public void run() { 158 if (policy.isPresent()) { 159 StrictMode.setThreadPolicy(policy.get()); 160 } 161 // Process class operates on the current thread. 162 Process.setThreadPriority(priority); 163 runnable.run(); 164 } 165 }); 166 } 167 }) 168 .build(); 169 } 170 171 private static ThreadPolicy getAsyncThreadPolicy() { 172 return new ThreadPolicy.Builder().detectAll().penaltyLog().build(); 173 } 174 175 private static ThreadPolicy getIoThreadPolicy() { 176 return new ThreadPolicy.Builder() 177 .detectNetwork() 178 .detectResourceMismatches() 179 .detectUnbufferedIo() 180 .penaltyLog() 181 .build(); 182 } 183 } 184