mirror of
https://github.com/Dark98/SliceBeam.git
synced 2026-07-03 00:38:53 +00:00
138 lines
4.2 KiB
Java
138 lines
4.2 KiB
Java
package ru.ytkab0bp.slicebeam.boot;
|
|
|
|
import android.util.Log;
|
|
import android.util.SparseBooleanArray;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.concurrent.CountDownLatch;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
import ru.ytkab0bp.slicebeam.BuildConfig;
|
|
|
|
public class AppBoot {
|
|
private final static String TAG = "boot";
|
|
|
|
static ExecutorService executor = Executors.newCachedThreadPool();
|
|
static List<BootTask> tasks;
|
|
static List<Runnable> pendingMain = new ArrayList<>();
|
|
static List<BootTask> pendingTasks = new ArrayList<>();
|
|
static SparseBooleanArray completed = new SparseBooleanArray();
|
|
static CountDownLatch latch;
|
|
|
|
public static void run(List<BootTask> tasks) {
|
|
long start = System.currentTimeMillis();
|
|
AppBoot.tasks = tasks;
|
|
int size = tasks.size();
|
|
for (int i = 0, s = tasks.size(); i < s; i++) {
|
|
BootTask task = tasks.get(i);
|
|
if (task.nonCritical) {
|
|
if (!task.workerThread) {
|
|
throw new IllegalArgumentException("Can't schedule non-critical task on main thread");
|
|
}
|
|
size--;
|
|
}
|
|
}
|
|
AppBoot.latch = new CountDownLatch(size);
|
|
|
|
for (int i = 0, s = tasks.size(); i < s; i++) {
|
|
BootTask task = tasks.get(i);
|
|
task.index = i;
|
|
tryRunTask(task, true, false);
|
|
}
|
|
try {
|
|
while (!latch.await(10, TimeUnit.MILLISECONDS)) {
|
|
if (!pendingMain.isEmpty()) {
|
|
List<Runnable> clone = new ArrayList<>(pendingMain);
|
|
for (Runnable r : clone) {
|
|
r.run();
|
|
}
|
|
pendingMain.removeAll(clone);
|
|
}
|
|
}
|
|
if (BuildConfig.DEBUG) {
|
|
Log.d(TAG, "Boot in " + (System.currentTimeMillis() - start) + "ms");
|
|
}
|
|
tryShutdown();
|
|
} catch (InterruptedException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
private static void tryShutdown() {
|
|
if (completed.size() == tasks.size()) {
|
|
executor.shutdown();
|
|
executor = null;
|
|
tasks = null;
|
|
pendingMain = null;
|
|
pendingTasks = null;
|
|
completed = null;
|
|
latch = null;
|
|
}
|
|
}
|
|
|
|
private static void tryRunTask(BootTask task, boolean fromMain, boolean isContinue) {
|
|
if (checkDependencies(task.dependencies)) {
|
|
Runnable r = () -> {
|
|
try {
|
|
task.run.run();
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "Error while executing boot task", e);
|
|
}
|
|
completed.put(task.index, true);
|
|
if (BuildConfig.DEBUG) {
|
|
Log.d(TAG, "Finish " + task);
|
|
}
|
|
if (!task.nonCritical) {
|
|
latch.countDown();
|
|
} else {
|
|
tryShutdown();
|
|
}
|
|
|
|
if (!isContinue) {
|
|
continueTasks(fromMain);
|
|
}
|
|
};
|
|
if (task.workerThread) {
|
|
executor.submit(r);
|
|
} else {
|
|
if (fromMain) {
|
|
r.run();
|
|
} else {
|
|
pendingMain.add(r);
|
|
}
|
|
}
|
|
} else {
|
|
pendingTasks.add(task);
|
|
}
|
|
}
|
|
|
|
private static void continueTasks(boolean fromMain) {
|
|
for (Iterator<BootTask> it = pendingTasks.iterator(); it.hasNext();) {
|
|
BootTask task = it.next();
|
|
if (checkDependencies(task.dependencies)) {
|
|
tryRunTask(task, fromMain, true);
|
|
it.remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static boolean checkDependencies(List<Class<?>> clzs) {
|
|
if (clzs.isEmpty()) {
|
|
return true;
|
|
}
|
|
|
|
for (int i = 0, s = tasks.size(); i < s; i++) {
|
|
if (clzs.contains(tasks.get(i).getClass())) {
|
|
if (!completed.get(i)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|