libutils clean-up

Change-Id: I11ee943da23a66828455a9770fc3c5ceb4bbcaa9
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 7934757..635f19b 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -24,6 +24,7 @@
 	Resource.cpp \
     pseudolocalize.cpp \
     SourcePos.cpp \
+	WorkQueue.cpp \
     ZipEntry.cpp \
     ZipFile.cpp
 
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index 3930117..872d95c 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -8,10 +8,13 @@
 #include "ResourceTable.h"
 #include "ResourceFilter.h"
 
+#include <androidfw/misc.h>
+
 #include <utils/Log.h>
 #include <utils/threads.h>
 #include <utils/List.h>
 #include <utils/Errors.h>
+#include <utils/misc.h>
 
 #include <sys/types.h>
 #include <dirent.h>
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index cd6870d..d617928 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -14,7 +14,7 @@
 #include "FileFinder.h"
 #include "CacheUpdater.h"
 
-#include <utils/WorkQueue.h>
+#include "WorkQueue.h"
 
 #if HAVE_PRINTF_ZD
 #  define ZD "%zd"
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index 16050b2..1b3abfd 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -12,7 +12,6 @@
 
 #include <androidfw/ResourceTypes.h>
 #include <utils/String16.h>
-#include <utils/TextOutput.h>
 #include <utils/TypeHelpers.h>
 
 #include <sys/types.h>
diff --git a/tools/aapt/WorkQueue.cpp b/tools/aapt/WorkQueue.cpp
new file mode 100644
index 0000000..24a962f
--- /dev/null
+++ b/tools/aapt/WorkQueue.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "WorkQueue"
+
+#include <utils/Log.h>
+#include "WorkQueue.h"
+
+namespace android {
+
+// --- WorkQueue ---
+
+WorkQueue::WorkQueue(size_t maxThreads, bool canCallJava) :
+        mMaxThreads(maxThreads), mCanCallJava(canCallJava),
+        mCanceled(false), mFinished(false), mIdleThreads(0) {
+}
+
+WorkQueue::~WorkQueue() {
+    if (!cancel()) {
+        finish();
+    }
+}
+
+status_t WorkQueue::schedule(WorkUnit* workUnit, size_t backlog) {
+    AutoMutex _l(mLock);
+
+    if (mFinished || mCanceled) {
+        return INVALID_OPERATION;
+    }
+
+    if (mWorkThreads.size() < mMaxThreads
+            && mIdleThreads < mWorkUnits.size() + 1) {
+        sp<WorkThread> workThread = new WorkThread(this, mCanCallJava);
+        status_t status = workThread->run("WorkQueue::WorkThread");
+        if (status) {
+            return status;
+        }
+        mWorkThreads.add(workThread);
+        mIdleThreads += 1;
+    } else if (backlog) {
+        while (mWorkUnits.size() >= mMaxThreads * backlog) {
+            mWorkDequeuedCondition.wait(mLock);
+            if (mFinished || mCanceled) {
+                return INVALID_OPERATION;
+            }
+        }
+    }
+
+    mWorkUnits.add(workUnit);
+    mWorkChangedCondition.broadcast();
+    return OK;
+}
+
+status_t WorkQueue::cancel() {
+    AutoMutex _l(mLock);
+
+    return cancelLocked();
+}
+
+status_t WorkQueue::cancelLocked() {
+    if (mFinished) {
+        return INVALID_OPERATION;
+    }
+
+    if (!mCanceled) {
+        mCanceled = true;
+
+        size_t count = mWorkUnits.size();
+        for (size_t i = 0; i < count; i++) {
+            delete mWorkUnits.itemAt(i);
+        }
+        mWorkUnits.clear();
+        mWorkChangedCondition.broadcast();
+        mWorkDequeuedCondition.broadcast();
+    }
+    return OK;
+}
+
+status_t WorkQueue::finish() {
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        if (mFinished) {
+            return INVALID_OPERATION;
+        }
+
+        mFinished = true;
+        mWorkChangedCondition.broadcast();
+    } // release lock
+
+    // It is not possible for the list of work threads to change once the mFinished
+    // flag has been set, so we can access mWorkThreads outside of the lock here.
+    size_t count = mWorkThreads.size();
+    for (size_t i = 0; i < count; i++) {
+        mWorkThreads.itemAt(i)->join();
+    }
+    mWorkThreads.clear();
+    return OK;
+}
+
+bool WorkQueue::threadLoop() {
+    WorkUnit* workUnit;
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        for (;;) {
+            if (mCanceled) {
+                return false;
+            }
+
+            if (!mWorkUnits.isEmpty()) {
+                workUnit = mWorkUnits.itemAt(0);
+                mWorkUnits.removeAt(0);
+                mIdleThreads -= 1;
+                mWorkDequeuedCondition.broadcast();
+                break;
+            }
+
+            if (mFinished) {
+                return false;
+            }
+
+            mWorkChangedCondition.wait(mLock);
+        }
+    } // release lock
+
+    bool shouldContinue = workUnit->run();
+    delete workUnit;
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        mIdleThreads += 1;
+
+        if (!shouldContinue) {
+            cancelLocked();
+            return false;
+        }
+    } // release lock
+
+    return true;
+}
+
+// --- WorkQueue::WorkThread ---
+
+WorkQueue::WorkThread::WorkThread(WorkQueue* workQueue, bool canCallJava) :
+        Thread(canCallJava), mWorkQueue(workQueue) {
+}
+
+WorkQueue::WorkThread::~WorkThread() {
+}
+
+bool WorkQueue::WorkThread::threadLoop() {
+    return mWorkQueue->threadLoop();
+}
+
+};  // namespace android
diff --git a/tools/aapt/WorkQueue.h b/tools/aapt/WorkQueue.h
new file mode 100644
index 0000000..d38f05d
--- /dev/null
+++ b/tools/aapt/WorkQueue.h
@@ -0,0 +1,119 @@
+/*]
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef AAPT_WORK_QUEUE_H
+#define AAPT_WORK_QUEUE_H
+
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+namespace android {
+
+/*
+ * A threaded work queue.
+ *
+ * This class is designed to make it easy to run a bunch of isolated work
+ * units in parallel, using up to the specified number of threads.
+ * To use it, write a loop to post work units to the work queue, then synchronize
+ * on the queue at the end.
+ */
+class WorkQueue {
+public:
+    class WorkUnit {
+    public:
+        WorkUnit() { }
+        virtual ~WorkUnit() { }
+
+        /*
+         * Runs the work unit.
+         * If the result is 'true' then the work queue continues scheduling work as usual.
+         * If the result is 'false' then the work queue is canceled.
+         */
+        virtual bool run() = 0;
+    };
+
+    /* Creates a work queue with the specified maximum number of work threads. */
+    WorkQueue(size_t maxThreads, bool canCallJava = true);
+
+    /* Destroys the work queue.
+     * Cancels pending work and waits for all remaining threads to complete.
+     */
+    ~WorkQueue();
+
+    /* Posts a work unit to run later.
+     * If the work queue has been canceled or is already finished, returns INVALID_OPERATION
+     * and does not take ownership of the work unit (caller must destroy it itself).
+     * Otherwise, returns OK and takes ownership of the work unit (the work queue will
+     * destroy it automatically).
+     *
+     * For flow control, this method blocks when the size of the pending work queue is more
+     * 'backlog' times the number of threads.  This condition reduces the rate of entry into
+     * the pending work queue and prevents it from growing much more rapidly than the
+     * work threads can actually handle.
+     *
+     * If 'backlog' is 0, then no throttle is applied.
+     */
+    status_t schedule(WorkUnit* workUnit, size_t backlog = 2);
+
+    /* Cancels all pending work.
+     * If the work queue is already finished, returns INVALID_OPERATION.
+     * If the work queue is already canceled, returns OK and does nothing else.
+     * Otherwise, returns OK, discards all pending work units and prevents additional
+     * work units from being scheduled.
+     *
+     * Call finish() after cancel() to wait for all remaining work to complete.
+     */
+    status_t cancel();
+
+    /* Waits for all work to complete.
+     * If the work queue is already finished, returns INVALID_OPERATION.
+     * Otherwise, waits for all work to complete and returns OK.
+     */
+    status_t finish();
+
+private:
+    class WorkThread : public Thread {
+    public:
+        WorkThread(WorkQueue* workQueue, bool canCallJava);
+        virtual ~WorkThread();
+
+    private:
+        virtual bool threadLoop();
+
+        WorkQueue* const mWorkQueue;
+    };
+
+    status_t cancelLocked();
+    bool threadLoop(); // called from each work thread
+
+    const size_t mMaxThreads;
+    const bool mCanCallJava;
+
+    Mutex mLock;
+    Condition mWorkChangedCondition;
+    Condition mWorkDequeuedCondition;
+
+    bool mCanceled;
+    bool mFinished;
+    size_t mIdleThreads;
+    Vector<sp<WorkThread> > mWorkThreads;
+    Vector<WorkUnit*> mWorkUnits;
+};
+
+}; // namespace android
+
+#endif // AAPT_WORK_QUEUE_H
diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp
index 3994c31..8057068 100644
--- a/tools/aapt/ZipFile.cpp
+++ b/tools/aapt/ZipFile.cpp
@@ -20,8 +20,8 @@
 
 #define LOG_TAG "zip"
 
+#include <androidfw/ZipUtils.h>
 #include <utils/Log.h>
-#include <utils/ZipUtils.h>
 
 #include "ZipFile.h"