/*
* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.android.server.pm;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import android.util.Log;
public class MultiTaskDealer {
public static final String TAG = "MultiTaskDealer";
public static final String PACKAGEMANAGER_SCANER = "packagescan";
private static final boolean DEBUG_TASK = false;
private static HashMap<String, WeakReference<MultiTaskDealer>> map = new HashMap<String, WeakReference<MultiTaskDealer>>();
public static MultiTaskDealer getDealer(String name) {
WeakReference<MultiTaskDealer> ref = map.get(name);
MultiTaskDealer dealer = ref!=null?ref.get():null;
return dealer;
}
public static MultiTaskDealer startDealer(String name,int taskCount) {
MultiTaskDealer dealer = getDealer(name);
if(dealer==null) {
dealer = new MultiTaskDealer(name,taskCount);
WeakReference<MultiTaskDealer> ref = new WeakReference<MultiTaskDealer>(dealer);
map.put(name,ref);
}
return dealer;
}
public void startLock() {
mLock.lock();
}
public void endLock() {
mLock.unlock();
}
private ThreadPoolExecutor mExecutor;
private int mTaskCount = 0;
private boolean mNeedNotifyEnd = false;
private Object mObjWaitAll = new Object();
private ReentrantLock mLock = new ReentrantLock();
public MultiTaskDealer(String name,int taskCount) {
final String taskName = name;
ThreadFactory factory = new ThreadFactory()
{
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(final Runnable r) {
if (DEBUG_TASK) Log.d(TAG, "create a new thread:" + taskName);
return new Thread(r, taskName + "-" + mCount.getAndIncrement());
}
};
mExecutor = new ThreadPoolExecutor(taskCount, taskCount, 5, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(), factory){
protected void afterExecute(Runnable r, Throwable t) {
if(t!=null) {
t.printStackTrace();
}
MultiTaskDealer.this.TaskCompleteNotify(r);
if (DEBUG_TASK) Log.d(TAG, "end task");
super.afterExecute(r,t);
}
protected void beforeExecute(Thread t, Runnable r) {
if (DEBUG_TASK) Log.d(TAG, "start task");
super.beforeExecute(t,r);
}
};
}
public void addTask(Runnable task) {
synchronized (mObjWaitAll) {
mTaskCount+=1;
}
mExecutor.execute(task);
if (DEBUG_TASK) Log.d(TAG, "addTask");
}
private void TaskCompleteNotify(Runnable task) {
synchronized (mObjWaitAll) {
mTaskCount-=1;
if(mTaskCount<=0 && mNeedNotifyEnd) {
if (DEBUG_TASK) Log.d(TAG, "complete notify");
mObjWaitAll.notify();
}
}
}
public void waitAll() {
if (DEBUG_TASK) Log.d(TAG, "start wait all");
synchronized (mObjWaitAll) {
if(mTaskCount>0) {
mNeedNotifyEnd = true;
try {
mObjWaitAll.wait();
} catch (Exception e) {
}
mNeedNotifyEnd = false;
}
if (DEBUG_TASK) Log.d(TAG, "wait finish");
return;
}
}
}