Merge "Fix OVERRIDE_BUILT_MODULE_PATH for prebuilt shared libraries." into ics-factoryrom
diff --git a/core/Makefile b/core/Makefile
index 837b300..93dda66 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -1393,12 +1393,6 @@
 #
 #SDK_GNU_ERROR := true
 
-ifeq ($(HOST_OS),darwin)
-HOST_STRIP_SDK_LLVM := strip
-else
-HOST_STRIP_SDK_LLVM := strip --strip-all
-endif
-
 $(INTERNAL_SDK_TARGET): $(deps)
 	@echo "Package SDK: $@"
 	$(hide) rm -rf $(PRIVATE_DIR) $@
@@ -1428,9 +1422,6 @@
 				$(PRIVATE_DIR)/platforms/android-$(PLATFORM_VERSION)/images/$(TARGET_CPU_ABI)/NOTICE.txt && \
 		cp -f $(tools_notice_file_txt) $(PRIVATE_DIR)/tools/NOTICE.txt && \
 		cp -f $(tools_notice_file_txt) $(PRIVATE_DIR)/platform-tools/NOTICE.txt && \
-		for f in $(PRIVATE_DIR)/platform-tools/llvm-rs-cc-* ; do \
-			if [ -f "$$f" ]; then $(HOST_STRIP_SDK_LLVM) "$$f"; fi; \
-		done && \
 		HOST_OUT_EXECUTABLES=$(HOST_OUT_EXECUTABLES) HOST_OS=$(HOST_OS) \
 			development/build/tools/sdk_clean.sh $(PRIVATE_DIR) && \
 		chmod -R ug+rwX $(PRIVATE_DIR) && \
diff --git a/core/main.mk b/core/main.mk
index 1f03355..6841b36 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -415,6 +415,7 @@
 	external/zlib \
 	frameworks/base \
 	frameworks/compile \
+	sdk/avdlauncher \
 	sdk/emulator/mksdcard \
 	sdk/sdklauncher \
 	system/core/adb \
diff --git a/tools/atree/atree.cpp b/tools/atree/atree.cpp
index aee2b3c..2ba284f 100644
--- a/tools/atree/atree.cpp
+++ b/tools/atree/atree.cpp
@@ -1,6 +1,8 @@
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <stdarg.h>
 #include "options.h"
 #include "files.h"
 #include "fs.h"
@@ -10,7 +12,7 @@
 
 using namespace std;
 
-bool g_debug = false;
+bool g_debug = getenv("ATREE_DEBUG") != NULL;
 vector<string> g_listFiles;
 vector<string> g_inputBases;
 map<string, string> g_variables;
@@ -33,6 +35,7 @@
 "  -m DEPENDENCY  Output a make-formatted file containing the list.\n"
 "                 of files included.  It sets the variable ATREE_FILES.\n"
 "  -v VAR=VAL     Replaces ${VAR} by VAL when reading input files.\n"
+"  -d             Verbose debug mode.\n"
 "\n"
 "FILELIST file format:\n"
 "  The FILELIST files contain the list of files that will end up\n"
@@ -42,11 +45,13 @@
 "  In a FILELIST file, comment lines start with a #.  Other lines\n"
 "  are of the format:\n"
 "\n"
-"    DEST\n"
-"    SRC DEST\n"
+"    [rm|strip] DEST\n"
+"    SRC [strip] DEST\n"
 "    -SRCPATTERN\n"
 "\n"
 "  DEST should be path relative to the output directory.\n"
+"  'rm DEST' removes the destination file and fails if it's missing.\n"
+"  'strip DEST' strips the binary destination file.\n"
 "  If SRC is supplied, the file names can be different.\n"
 "  SRCPATTERN is a pattern for the filenames.\n"
 "\n";
@@ -72,13 +77,26 @@
     return true;
 }
 
+static void
+debug_printf(const char* format, ...)
+{
+    if (g_debug) {
+        fflush(stderr);
+        va_list ap;
+        va_start(ap, format);
+        vprintf(format, ap);
+        va_end(ap);
+        fflush(stdout);
+    }
+}
+
 int
 main(int argc, char* const* argv)
 {
     int err;
     bool done = false;
     while (!done) {
-        int opt = getopt(argc, argv, "f:I:o:hlm:v:");
+        int opt = getopt(argc, argv, "f:I:o:hlm:v:d");
         switch (opt)
         {
             case -1:
@@ -117,6 +135,9 @@
                     return usage();
                 }
                 break;
+            case 'd':
+                g_debug = true;
+                break;
             default:
             case '?':
             case 'h':
@@ -169,7 +190,7 @@
 
     // read file lists
     for (vector<string>::iterator it=g_listFiles.begin();
-                                it!=g_listFiles.end(); it++) {
+                                 it!=g_listFiles.end(); it++) {
         err = read_list_file(*it, g_variables, &files, &excludes);
         if (err != 0) {
             return err;
@@ -181,9 +202,8 @@
     for (vector<FileRecord>::iterator it=files.begin();
                                 it!=files.end(); it++) {
         err |= locate(&(*it), g_inputBases);
-
     }
-    
+
     // expand the directories that we should copy into a list of files
     for (vector<FileRecord>::iterator it=files.begin();
                                 it!=files.end(); it++) {
@@ -219,8 +239,8 @@
         }
     }
 
-    // gather files that should become directores and directories that should
-    // become files
+    // gather files that should become directores
+    // and directories that should become files
     for (vector<FileRecord>::iterator it=files.begin();
                                 it!=files.end(); it++) {
         if (it->outMod != 0 && it->sourceIsDir != it->outIsDir) {
@@ -231,48 +251,66 @@
     // delete files
     for (set<string>::iterator it=deleted.begin();
                                 it!=deleted.end(); it++) {
-        if (g_debug) {
-            printf("deleting %s\n", it->c_str());
-        }
+        debug_printf("deleting %s\n", it->c_str());
         err = remove_recursively(*it);
         if (err != 0) {
             return err;
         }
     }
 
+    // remove all files or directories as requested from the input atree file.
+    // must be done before create new directories.
+    for (vector<FileRecord>::iterator it=files.begin();
+                                it!=files.end(); it++) {
+        if (!it->sourceIsDir) {
+            if (it->fileOp == FILE_OP_REMOVE &&
+                    deleted.count(it->outPath) == 0) {
+                debug_printf("remove %s\n", it->outPath.c_str());
+                err = remove_recursively(it->outPath);
+                if (err != 0) {
+                    return err;
+                }
+            }
+        }
+    }
+
     // make directories
     for (set<string>::iterator it=directories.begin();
                                 it!=directories.end(); it++) {
-        if (g_debug) {
-            printf("mkdir %s\n", it->c_str());
-        }
+        debug_printf("mkdir %s\n", it->c_str());
         err = mkdir_recursively(*it);
         if (err != 0) {
             return err;
         }
     }
 
-    // copy (or link) files
+    // copy (or link) files that are newer or of different size
     for (vector<FileRecord>::iterator it=files.begin();
                                 it!=files.end(); it++) {
         if (!it->sourceIsDir) {
-            if (g_debug) {
-                printf("copy %s(%ld) ==> %s(%ld)", it->sourcePath.c_str(),
-                    it->sourceMod, it->outPath.c_str(), it->outMod);
-                fflush(stdout);
+            if (it->fileOp == FILE_OP_REMOVE) {
+                continue;
             }
 
-            if (it->outMod < it->sourceMod) {
+            debug_printf("copy %s(%ld) ==> %s(%ld)",
+                it->sourcePath.c_str(), it->sourceMod,
+                it->outPath.c_str(), it->outMod);
+
+            if (it->outSize != it->sourceSize || it->outMod < it->sourceMod) {
                 err = copy_file(it->sourcePath, it->outPath);
-                if (g_debug) {
-                    printf(" done.\n");
-                }
+                debug_printf(" done.\n");
                 if (err != 0) {
                     return err;
                 }
             } else {
-                if (g_debug) {
-                    printf(" skipping.\n");
+                debug_printf(" skipping.\n");
+            }
+
+            if (it->fileOp == FILE_OP_STRIP) {
+                debug_printf("strip %s\n", it->outPath.c_str());
+                err = strip_file(it->outPath);
+                if (err != 0) {
+                    return err;
                 }
             }
         }
diff --git a/tools/atree/files.cpp b/tools/atree/files.cpp
index d4866d4..df3e987 100644
--- a/tools/atree/files.cpp
+++ b/tools/atree/files.cpp
@@ -62,7 +62,7 @@
 split_line(const char* p, vector<string>* out)
 {
     const char* q = p;
-    enum { WHITE, TEXT } state = WHITE;
+    enum { WHITE, TEXT, IN_QUOTE } state = WHITE;
     while (*p) {
         if (*p == '#') {
             break;
@@ -73,13 +73,25 @@
             case WHITE:
                 if (!isspace(*p)) {
                     q = p;
-                    state = TEXT;
+                    state = (*p == '"') ? IN_QUOTE : TEXT;
                 }
                 break;
+            case IN_QUOTE:
+                if (*p == '"') {
+                    state = TEXT;
+                    break;
+                }
+                // otherwise fall-through to TEXT case
             case TEXT:
-                if (isspace(*p)) {
+                if (state != IN_QUOTE && isspace(*p)) {
                     if (q != p) {
-                        out->push_back(string(q, p-q));
+                        const char* start = q;
+                        size_t len = p-q;
+                        if (len > 2 && *start == '"' && start[len - 1] == '"') {
+                            start++;
+                            len -= 2;
+                        }
+                        out->push_back(string(start, len));
                     }
                     state = WHITE;
                 }
@@ -88,17 +100,25 @@
         p++;
     }
     if (state == TEXT) {
-        out->push_back(string(q, p-q));
+        const char* start = q;
+        size_t len = p-q;
+        if (len > 2 && *start == '"' && start[len - 1] == '"') {
+            start++;
+            len -= 2;
+        }
+        out->push_back(string(start, len));
     }
 }
 
 static void
-add_file(vector<FileRecord>* files, const string& listFile, int listLine,
+add_file(vector<FileRecord>* files, const FileOpType fileOp,
+            const string& listFile, int listLine,
             const string& sourceName, const string& outName)
 {
     FileRecord rec;
     rec.listFile = listFile;
     rec.listLine = listLine;
+    rec.fileOp = fileOp;
     rec.sourceName = sourceName;
     rec.outName = outName;
     files->push_back(rec);
@@ -182,7 +202,7 @@
         err = errno;
         goto cleanup;
     }
-    
+
     size = ftell(f);
 
     err = fseek(f, 0, SEEK_SET);
@@ -245,35 +265,52 @@
             }
             printf("]\n");
 #endif
-            
-            if (words.size() == 1) {
-                // pattern: DEST
-                bool error = false;
-                string w0 = replace_variables(words[0], variables, &error);
-                if (error) {
-                    err = 1;
-                    goto cleanup;
+            FileOpType op = FILE_OP_COPY;
+            string paths[2];
+            int pcount = 0;
+            string errstr;
+            for (vector<string>::iterator it = words.begin(); it != words.end(); ++it) {
+                const string& word = *it;
+                if (word == "rm") {
+                    if (op != FILE_OP_COPY) {
+                        errstr = "Error: you can only specifiy 'rm' or 'strip' once per line.";
+                        break;
+                    }
+                    op = FILE_OP_REMOVE;
+                } else if (word == "strip") {
+                    if (op != FILE_OP_COPY) {
+                        errstr = "Error: you can only specifiy 'rm' or 'strip' once per line.";
+                        break;
+                    }
+                    op = FILE_OP_STRIP;
+                } else if (pcount < 2) {
+                    bool error = false;
+                    paths[pcount++] = replace_variables(word, variables, &error);
+                    if (error) {
+                        err = 1;
+                        goto cleanup;
+                    }
+                } else {
+                    errstr = "Error: More than 2 paths per line.";
+                    break;
                 }
-                add_file(files, filename, i+1, w0, w0);
             }
-            else if (words.size() == 2) {
-                // pattern: SRC DEST
-                bool error = false;
-                string w0, w1;
-                w0 = replace_variables(words[0], variables, &error);
-                if (!error) {
-                    w1 = replace_variables(words[1], variables, &error);
-                }
-                if (error) {
-                    err = 1;
-                    goto cleanup;
-                }
-                add_file(files, filename, i+1, w0, w1);
+
+            if (pcount == 0 && !errstr.empty()) {
+                errstr = "Error: No path found on line.";
             }
-            else {
-                fprintf(stderr, "%s:%d: bad format: %s\n", filename.c_str(),
-                        i+1, p);
+
+            if (!errstr.empty()) {
+                fprintf(stderr, "%s:%d: bad format: %s\n%s\nExpected: [SRC] [rm|strip] DEST\n",
+                        filename.c_str(), i+1, p, errstr.c_str());
                 err = 1;
+            } else {
+                if (pcount == 1) {
+                    // pattern: [rm|strip] DEST
+                    paths[1] = paths[0];
+                }
+
+                add_file(files, op, filename, i+1, paths[0], paths[1]);
             }
         }
         p = q;
@@ -293,6 +330,14 @@
 int
 locate(FileRecord* rec, const vector<string>& search)
 {
+    if (rec->fileOp == FILE_OP_REMOVE) {
+        // Don't touch source files when removing a destination.
+        rec->sourceMod = 0;
+        rec->sourceSize = 0;
+        rec->sourceIsDir = false;
+        return 0;
+    }
+
     int err;
 
     for (vector<string>::const_iterator it=search.begin();
@@ -304,6 +349,7 @@
             rec->sourceBase = *it;
             rec->sourcePath = full;
             rec->sourceMod = st.st_mtime;
+            rec->sourceSize = st.st_size;
             rec->sourceIsDir = S_ISDIR(st.st_mode);
             return 0;
         }
@@ -324,9 +370,11 @@
     err = stat(rec->outPath.c_str(), &st);
     if (err == 0) {
         rec->outMod = st.st_mtime;
+        rec->outSize = st.st_size;
         rec->outIsDir = S_ISDIR(st.st_mode);
     } else {
         rec->outMod = 0;
+        rec->outSize = 0;
         rec->outIsDir = false;
     }
 }
@@ -427,3 +475,8 @@
 {
     return list_dir("", rec, excludes, files);
 }
+
+FileRecord::FileRecord() {
+    fileOp = FILE_OP_COPY;
+}
+
diff --git a/tools/atree/files.h b/tools/atree/files.h
index 6480c98..f6bf8a6 100644
--- a/tools/atree/files.h
+++ b/tools/atree/files.h
@@ -8,8 +8,16 @@
 
 using namespace std;
 
+enum FileOpType {
+    FILE_OP_COPY = 0,
+    FILE_OP_REMOVE,
+    FILE_OP_STRIP
+};
+
 struct FileRecord
 {
+    FileRecord();
+
     string listFile;
     int listLine;
 
@@ -18,9 +26,12 @@
     string sourcePath;
     bool sourceIsDir;
     time_t sourceMod;
+    off_t  sourceSize;
+    FileOpType fileOp;
 
     string outName;
     string outPath;
+    off_t  outSize;
     time_t outMod;
     bool outIsDir;
     unsigned int mode;
diff --git a/tools/atree/fs.cpp b/tools/atree/fs.cpp
index 9971879..b648394 100644
--- a/tools/atree/fs.cpp
+++ b/tools/atree/fs.cpp
@@ -1,7 +1,9 @@
 #include "fs.h"
 #include "files.h"
 #include <unistd.h>
+#include <stdlib.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <dirent.h>
 #include <string>
 #include <vector>
@@ -64,10 +66,10 @@
 #ifdef HAVE_DIRENT_D_TYPE
             bool is_directory = (ent->d_type == DT_DIR);
 #else
-	    	// If dirent.d_type is missing, then use stat instead
-			struct stat stat_buf;
-			stat(full.c_str(), &stat_buf);
-			bool is_directory = S_ISDIR(stat_buf.st_mode);
+            // If dirent.d_type is missing, then use stat instead
+            struct stat stat_buf;
+            stat(full.c_str(), &stat_buf);
+            bool is_directory = S_ISDIR(stat_buf.st_mode);
 #endif
             if (is_directory) {
                 dirs.push_back(full);
@@ -146,3 +148,27 @@
                     COPY_NO_DEREFERENCE | COPY_FORCE | COPY_PERMISSIONS);
     return err;
 }
+
+int
+strip_file(const string& path)
+{
+    // Default strip command to run is "strip" unless overridden by the STRIP env var.
+    const char* strip_cmd = getenv("STRIP");
+    if (!strip_cmd || !strip_cmd[0]) {
+        strip_cmd = "strip";
+    }
+    pid_t pid = fork();
+    if (pid == -1) {
+        // Fork failed. errno should be set.
+        return -1;
+    } else if (pid == 0) {
+        // Exec in the child. Only returns if execve failed.
+        return execlp(strip_cmd, strip_cmd, path.c_str(), (char *)NULL);
+    } else {
+        // Wait for child pid and return its exit code.
+        int status;
+        waitpid(pid, &status, 0);
+        return status;
+    }
+}
+
diff --git a/tools/atree/fs.h b/tools/atree/fs.h
index 4080880..fd4ae3e 100644
--- a/tools/atree/fs.h
+++ b/tools/atree/fs.h
@@ -8,5 +8,6 @@
 int remove_recursively(const string& path);
 int mkdir_recursively(const string& path);
 int copy_file(const string& src, const string& dst);
+int strip_file(const string& path);
 
 #endif // FS_H