FontRequestThreadPool.java
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.core.provider;
import android.os.Handler;
import android.os.Process;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
class FontRequestThreadPool {
private final ThreadPoolExecutor mExecutor;
private final ThreadFactory mThreadFactory;
FontRequestThreadPool(
@NonNull String threadName,
int threadPriority,
@IntRange(from = 0) int keepAliveTimeInMillis
) {
mThreadFactory = new ThreadFactory(threadName, threadPriority);
// allow core thread timeout to timeout the core threads so that
// when no tasks arrive, the core threads can be killed
mExecutor = new ThreadPoolExecutor(
0 /* corePoolSize */,
1 /* maximumPoolSize */,
keepAliveTimeInMillis /* keepAliveTime */,
TimeUnit.MILLISECONDS /* keepAliveTime TimeUnit */,
new LinkedBlockingDeque<Runnable>() /* unbounded queue*/,
mThreadFactory
);
mExecutor.allowCoreThreadTimeOut(true);
}
<T> T postAndWait(
@NonNull final Callable<T> callable,
@IntRange(from = 0) int timeoutMillis
) throws InterruptedException {
Future<T> future = mExecutor.submit(callable);
try {
return future.get(timeoutMillis, TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw e;
} catch (TimeoutException e) {
throw new InterruptedException("timeout");
}
}
<T> void postAndReply(
@NonNull final Callable<T> callable,
@NonNull final ReplyCallback<T> callback
) {
final Handler calleeHandler = CalleeHandler.create();
mExecutor.execute(new Runnable() {
@Override
public void run() {
T t;
try {
t = callable.call();
} catch (Exception e) {
t = null;
}
final T result = t;
calleeHandler.post(new Runnable() {
@Override
public void run() {
callback.onReply(result);
}
});
}
});
}
// TODO Remove
@VisibleForTesting
boolean isRunning() {
return mExecutor.getPoolSize() != 0;
}
/**
* Reply callback for postAndReply
*
* @param <T> A type which will be received as the argument.
*/
interface ReplyCallback<T> {
/**
* Called when the task was finished.
*/
void onReply(T value);
}
private static class ThreadFactory implements java.util.concurrent.ThreadFactory {
private String mThreadName;
private int mPriority;
ThreadFactory(@NonNull String threadName, int priority) {
mThreadName = threadName;
mPriority = priority;
}
@Override
public Thread newThread(Runnable runnable) {
return new ProcessPriorityThread(runnable, mThreadName, mPriority);
}
private static class ProcessPriorityThread extends Thread {
private final int mPriority;
ProcessPriorityThread(Runnable target, String name, int priority) {
super(target, name);
mPriority = priority;
}
@Override
public void run() {
Process.setThreadPriority(mPriority);
super.run();
}
}
}
}