Stop worker threads on memory trim & fix bad pointer access

Change-Id: I6fe7e31aeb6dd41fa65ab952caed97bc2da510d7
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index dc3a4e2..57d1a4f 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -310,6 +310,7 @@
             fontRenderer->flush();
             textureCache.flush();
             pathCache.clear();
+            tasks.stop();
             // fall through
         case kFlushMode_Layers:
             layerCache.clear();
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 490c22a..07c4207 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -347,14 +347,15 @@
 // Paths
 ///////////////////////////////////////////////////////////////////////////////
 
-void PathCache::remove(SkPath* path) {
+void PathCache::remove(const path_pair_t& pair) {
     Vector<PathDescription> pathsToRemove;
     LruCache<PathDescription, PathTexture*>::Iterator i(mCache);
 
     while (i.next()) {
         const PathDescription& key = i.key();
         if (key.type == kShapePath &&
-                (key.shape.path.mPath == path || key.shape.path.mPath == path->getSourcePath())) {
+                (key.shape.path.mPath == pair.getFirst() ||
+                        key.shape.path.mPath == pair.getSecond())) {
             pathsToRemove.push(key);
         }
     }
@@ -366,7 +367,7 @@
 
 void PathCache::removeDeferred(SkPath* path) {
     Mutex::Autolock l(mLock);
-    mGarbage.push(path);
+    mGarbage.push(path_pair_t(path, const_cast<SkPath*>(path->getSourcePath())));
 }
 
 void PathCache::clearGarbage() {
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index e6d92df..1467231 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -26,6 +26,7 @@
 #include "Debug.h"
 #include "Properties.h"
 #include "Texture.h"
+#include "utils/Pair.h"
 
 class SkBitmap;
 class SkCanvas;
@@ -215,10 +216,6 @@
     PathTexture* get(SkPath* path, SkPaint* paint);
 
     /**
-     * Removes an entry.
-     */
-    void remove(SkPath* path);
-    /**
      * Removes the specified path. This is meant to be called from threads
      * that are not the EGL context thread.
      */
@@ -251,6 +248,8 @@
             float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
 
 private:
+    typedef Pair<SkPath*, SkPath*> path_pair_t;
+
     PathTexture* addTexture(const PathDescription& entry,
             const SkPath *path, const SkPaint* paint);
     PathTexture* addTexture(const PathDescription& entry, SkBitmap* bitmap);
@@ -261,6 +260,12 @@
     }
 
     /**
+     * Removes an entry.
+     * The pair must define first=path, second=sourcePath
+     */
+    void remove(const path_pair_t& pair);
+
+    /**
      * Ensures there is enough space in the cache for a texture of the specified
      * dimensions.
      */
@@ -318,7 +323,8 @@
     bool mDebugEnabled;
 
     sp<PathProcessor> mProcessor;
-    Vector<SkPath*> mGarbage;
+
+    Vector<path_pair_t> mGarbage;
     mutable Mutex mLock;
 }; // class PathCache
 
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
index ce6c8c0..c8bfd9c 100644
--- a/libs/hwui/thread/TaskManager.cpp
+++ b/libs/hwui/thread/TaskManager.cpp
@@ -48,6 +48,12 @@
     return mThreads.size() > 0;
 }
 
+void TaskManager::stop() {
+    for (size_t i = 0; i < mThreads.size(); i++) {
+        mThreads[i]->exit();
+    }
+}
+
 bool TaskManager::addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor) {
     if (mThreads.size() > 0) {
         TaskWrapper wrapper(task, processor);
diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h
index bc86062..477314b 100644
--- a/libs/hwui/thread/TaskManager.h
+++ b/libs/hwui/thread/TaskManager.h
@@ -47,6 +47,12 @@
      */
     bool canRunTasks() const;
 
+    /**
+     * Stops all allocated threads. Adding tasks will start
+     * the threads again as necessary.
+     */
+    void stop();
+
 private:
     template <typename T>
     friend class TaskProcessor;
diff --git a/libs/hwui/utils/Pair.h b/libs/hwui/utils/Pair.h
new file mode 100644
index 0000000..172606a
--- /dev/null
+++ b/libs/hwui/utils/Pair.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 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 ANDROID_HWUI_PAIR_H
+#define ANDROID_HWUI_PAIR_H
+
+namespace android {
+namespace uirenderer {
+
+template <typename F, typename S>
+struct Pair {
+    F first;
+    S second;
+
+    Pair() { }
+    Pair(const Pair& o) : first(o.first), second(o.second) { }
+    Pair(const F& f, const S& s) : first(f), second(s)  { }
+
+    inline const F& getFirst() const {
+        return first;
+    }
+
+    inline const S& getSecond() const {
+        return second;
+    }
+};
+
+}; // namespace uirenderer
+
+template <typename F, typename S>
+struct trait_trivial_ctor< uirenderer::Pair<F, S> >
+{ enum { value = aggregate_traits<F, S>::has_trivial_ctor }; };
+template <typename F, typename S>
+struct trait_trivial_dtor< uirenderer::Pair<F, S> >
+{ enum { value = aggregate_traits<F, S>::has_trivial_dtor }; };
+template <typename F, typename S>
+struct trait_trivial_copy< uirenderer::Pair<F, S> >
+{ enum { value = aggregate_traits<F, S>::has_trivial_copy }; };
+template <typename F, typename S>
+struct trait_trivial_move< uirenderer::Pair<F, S> >
+{ enum { value = aggregate_traits<F, S>::has_trivial_move }; };
+
+}; // namespace android
+
+#endif // ANDROID_HWUI_PAIR_H