enum class LaunchPeriod(val value: Int) {
Init(0),
BeforeAttachBase(1),
AfterAttachBase(2),
BeforeOnCreate(3),
AfterOnCreate(4)
}
interface ILaunchTask : Runnable {
val id: String
fun runInMainThread(): Boolean
fun getEarliestPeriod(): LaunchPeriod?
fun getLatestPeriod(): LaunchPeriod
fun dependOn(): MutableList<String>
}
class LaunchTask(private val option: Option, private val toRun: () -> Unit) : ILaunchTask {
data class Option(
val id: String,
val inMainThread: Boolean,
val earliestPeriod: LaunchPeriod?,
val latestPeriod: LaunchPeriod,
val dependOn: MutableList<String>? = null
)
override val id = option.id
override fun runInMainThread(): Boolean = option.inMainThread
override fun getEarliestPeriod(): LaunchPeriod? = option.earliestPeriod
override fun getLatestPeriod(): LaunchPeriod = option.latestPeriod
override fun dependOn(): MutableList<String> = option.dependOn ?: mutableListOf()
override fun run() = toRun()
}
class TaskExtraInfo {
var priority = -1
var startTime = 0L
var endTime = 0L
val children = mutableListOf<ILaunchTask>()
val parent = mutableListOf<ILaunchTask>()
val dependent = mutableListOf<ILaunchTask>()
}
class RocketApplication : Application() {
private lateinit var initLoader: IAppInitLoader
private fun initAppLoader() {
initLoader = MainProcessInitLoader(this)
}
override fun attachBaseContext(base: Context) {
initAppLoader()
initLoader.attachBaseContext(base)
}
@SuppressLint("MissingSuperCall")
override fun onCreate() {
initLoader.onCreate()
}
}
interface IAppInitLoader {
fun attachBaseContext(base: Context)
fun onCreate()
}
class MainProcessInitLoader(private val application: RocketApplication) : IAppInitLoader {
val launchDispatcher = LaunchDispatcher(application) {
}
override fun attachBaseContext(base: Context) {
launchDispatcher.launch()
launchDispatcher.appAttachBase()
}
override fun onCreate() {
launchDispatcher.appOnCreate()
}
}
class LaunchDispatcher(application: RocketApplication, block: LaunchTaskContainer.() -> Unit) :
Runnable {
private val taskManager = LaunchTaskManager(application)
private val threadNumber = AtomicInteger(1)
private var dispatchThread: Thread? = null
private var launchTime = System.currentTimeMillis()
private val threadFactory = ThreadFactory {
Thread("Launcher")
}
private val executor: ExecutorService =
ThreadPoolExecutor(
8, 8,
0L, TimeUnit.MILLISECONDS, LinkedBlockingQueue(), threadFactory
)
init {
taskManager.block()
taskManager.classify()
}
fun launch() {
val dispatchThread = Thread(this)
dispatchThread.name = "LaunchDispatcher"
dispatchThread.start()
this.dispatchThread = dispatchThread
}
fun appAttachBase() {
takeMainThread()
}
fun appOnCreate() {
takeMainThread()
}
private fun takeMainThread() {
while (true) {
var task: ILaunchTask?
task = taskManager.takeUiReadyTaskIfExist()
if (task == null) {
synchronized(this) {
task = taskManager.takeNonUiTaskIfExist(10)
}
}
val localTask = task ?: continue
localTask.run()
if (localTask is MainThreadCompleteTask) {
logMainThreadCompleteTask(localTask.id)
break
}
}
}
override fun run() {
while (true) {
var task: ILaunchTask?
synchronized(this) {
task = taskManager.takeNonUiTaskIfExist()
}
val localTask = task ?: break
executor.execute {
localTask.run()
}
}
}
}
interface LaunchTaskContainer {
fun with(task: ILaunchTask)
}
class LaunchTaskManager(application: RocketApplication) : LaunchTaskContainer {
private val tmpTaskList: MutableList<ILaunchTask> = arrayListOf()
private val allCustomTask: MutableList<ILaunchTask> = arrayListOf()
private val appAttachBaseStart = AppOnAttachBaseStart()
private val superAttachBase = AppSuperAttachBase(application)
private val attachBaseComplete = AppAttachBaseCompleteTask()
private val appOnCreateStart = AppOnCreateStart()
private val superOnCreate = AppSuperOnCreate(application)
private val onCreateComplete = AppOnCreateCompleteTask()
private val unDispatchTask = mutableListOf<ILaunchTask>()
private val readyQueue = PriorityBlockingQueue<PriorityLaunchTask>()
private val uiReadyQueue = PriorityBlockingQueue<PriorityLaunchTask>()
private val taskExtra = ConcurrentHashMap<ILaunchTask, TaskExtraInfo>()
override fun with(task: ILaunchTask) {
tmpTaskList.add(task)
}
fun classify() {
initData()
initDepend()
initReadyQueue()
}
private fun initData() {
allCustomTask.clear()
allCustomTask.addAll(tmpTaskList)
tmpTaskList.clear()
allCustomTask.forEach { task ->
unDispatchTask.add(task)
}
unDispatchTask.add(superAttachBase)
unDispatchTask.add(superOnCreate)
unDispatchTask.add(attachBaseComplete)
unDispatchTask.add(onCreateComplete)
unDispatchTask.add(appOnCreateStart)
}
private fun initDepend() {
allCustomTask.forEach { task ->
genEarliestDepend(task, task.getEarliestPeriod())
genLatestDepend(task, task.getLatestPeriod())
genCommonDepend(task)
}
addDepend(superAttachBase, appAttachBaseStart)
addDepend(attachBaseComplete, superAttachBase)
addDepend(appOnCreateStart, attachBaseComplete)
addDepend(superOnCreate, appOnCreateStart)
addDepend(onCreateComplete, superOnCreate)
}
private fun initReadyQueue() {
readyQueue.clear()
val readyTasks = mutableListOf<ILaunchTask>()
for ((task, extra) in taskExtra) {
val dependent = extra.dependent
if (!dependent.isEmpty()) continue
readyTasks.add(task)
addReadyTask(task, getPriority(task))
}
for (task in readyTasks) unDispatchTask.remove(task)
}
private fun addReadyTask(task: ILaunchTask, priority: Int) {
val queue = if (task.runInMainThread()) uiReadyQueue else readyQueue
queue.add(PriorityLaunchTask(task, priority))
}
}
class PriorityLaunchTask(val task: ILaunchTask, private val priority: Int) :
Comparable<PriorityLaunchTask> {
override fun compareTo(other: PriorityLaunchTask) = -(this.priority - other.priority)
}