am 7793c09e: Merge changes I4e94b8b9,Iae48d489

* commit '7793c09ec42bf1a01a5f45f0e723f9a36fcfd9d7':
  Support for multiple modules with the same name is going away.
  Support for multiple modules with the same name is going away.
diff --git a/bugmailer/Android.mk b/bugmailer/Android.mk
index 1bb3099..c5aea4b 100644
--- a/bugmailer/Android.mk
+++ b/bugmailer/Android.mk
@@ -2,11 +2,11 @@
 #
 LOCAL_PATH:= $(call my-dir)
 
-ifneq ($(TARGET_BUILD_PDK), true)
+ifeq (platform,$(TARGET_BUILD_JAVA_SUPPORT_LEVEL))
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_MODULE := send_bug
 LOCAL_MODULE_TAGS := optional
 include $(BUILD_JAVA_LIBRARY)
-endif
+endif #JAVA_SUPPORT
diff --git a/bugmailer/bugmailer.sh b/bugmailer/bugmailer.sh
index 93d1c8a..225b18d 100755
--- a/bugmailer/bugmailer.sh
+++ b/bugmailer/bugmailer.sh
@@ -1,5 +1,7 @@
 #!/system/bin/sh
 
+# TODO: restructure this to keep bugreports entirely on internal storage
+
 # Do not allow bugreports on user builds unless USB debugging
 # is enabled.
 if [ "x$(getprop ro.build.type)" = "xuser" -a \
@@ -7,29 +9,44 @@
   exit 0
 fi
 
-timestamp=`date +'%Y-%m-%d-%H-%M-%S'`
-storagePath="$EXTERNAL_STORAGE/bugreports"
-bugreport=$storagePath/bugreport-$timestamp
-screenshotPath="$EXTERNAL_STORAGE/Pictures/Screenshots"
-screenshot=$screenshotPath/Screenshot_$timestamp.png
-
-# check screen shot folder
-if [ ! -e $screenshotPath ]; then
-  mkdir $screenshotPath
+# Use bugreport-specific paths if defined
+if [ -n "$BUGREPORT_WRITE_PATH" ]; then
+  writePath="$BUGREPORT_WRITE_PATH"
+else
+  writePath="$EXTERNAL_STORAGE"
 fi
+if [ -n "$BUGREPORT_READ_PATH" ]; then
+  readPath="$BUGREPORT_READ_PATH"
+else
+  readPath="$EXTERNAL_STORAGE"
+fi
+
+tmpPath="/data/local/tmp"
+bugreportPath="bugreports"
+screenshotPath="Pictures/Screenshots"
+
+# Create directories if needed
+if [ ! -e "$writePath/$bugreportPath" ]; then
+  mkdir "$writePath/$bugreportPath"
+fi
+if [ ! -e "$writePath/$screenshotPath" ]; then
+  mkdir "$writePath/$screenshotPath"
+fi
+
+timestamp=`date +'%Y-%m-%d-%H-%M-%S'`
 
 # take screen shot
 # we run this as a bg job in case screencap is stuck
-/system/bin/screencap -p $screenshot &
+/system/bin/screencap -p "$writePath/$screenshotPath/Screenshot_$timestamp.png" &
 
 # run bugreport
-/system/bin/dumpstate -o $bugreport $@
+/system/bin/dumpstate -o "$tmpPath/bugreport-$timestamp" $@
 
-
-# make files readable
-chown root.sdcard_rw $bugreport.txt
-chown root.sdcard_rw $screenshot
+# copy finished bugreport into place for sending
+cp "$tmpPath/bugreport-$timestamp.txt" "$writePath/$bugreportPath/bugreport-$timestamp.txt"
+# clean up any remaining files
+rm $tmpPath/bugreport*
 
 # invoke send_bug to look up email accounts and fire intents
 # make it convenient to send bugreport to oneself
-/system/bin/send_bug $bugreport.txt $screenshot
+/system/bin/send_bug "$readPath/$bugreportPath/bugreport-$timestamp.txt" "$readPath/$screenshotPath/Screenshot_$timestamp.png"
diff --git a/bugmailer/src/com/android/commands/sendbug/SendBug.java b/bugmailer/src/com/android/commands/sendbug/SendBug.java
index da8788e..f6d0db7 100644
--- a/bugmailer/src/com/android/commands/sendbug/SendBug.java
+++ b/bugmailer/src/com/android/commands/sendbug/SendBug.java
@@ -27,15 +27,18 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.util.Log;
 
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.regex.Pattern;
 
 public class SendBug {
 
-    private static final String GOOGLE_ACCOUNT_TYPE = "com.google";
-    private static final String EMAIL_ACCOUNT_TYPE = "com.android.email";
+    private static final String LOG_TAG = SendBug.class.getSimpleName();
+    private static final Pattern EMAIL_REGEX = Pattern.compile(
+            "^[\\w.%+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$");
     private static final String SEND_BUG_INTENT_ACTION = "android.testing.SEND_BUG";
 
     public static void main(String[] args) {
@@ -55,20 +58,16 @@
         File screenShot = null;
         if (screenShotPath != null) {
             screenShot = new File(screenShotPath);
-            if (!screenShot.exists()) {
-              // screen shot probably failed
-              screenShot = null;
-            }
         }
-        if (bugreport.exists()) {
-            final Uri bugreportUri = Uri.fromFile(bugreport);
-            // todo (aalbert): investigate adding a screenshot to BugReporter
-            Intent intent = tryBugReporter(bugreportUri);
-            if (intent == null) {
-                final Uri screenshotUri = screenShot != null
-                        ? Uri.fromFile(screenShot) : null;
-                intent = getSendMailIntent(bugreportUri, screenshotUri);
-            }
+        final Uri bugreportUri = Uri.fromFile(bugreport);
+        // todo (aalbert): investigate adding a screenshot to BugReporter
+        Intent intent = tryBugReporter(bugreportUri);
+        if (intent == null) {
+            final Uri screenshotUri = screenShot != null
+                    ? Uri.fromFile(screenShot) : null;
+            intent = getSendMailIntent(bugreportUri, screenshotUri);
+        }
+        if (intent != null) {
             final IActivityManager mAm = ActivityManagerNative.getDefault();
             try {
                 mAm.startActivity(null, intent, intent.getType(), null, null, 0, 0,
@@ -76,6 +75,9 @@
             } catch (RemoteException e) {
                 // ignore
             }
+        } else {
+            Log.w(LOG_TAG, "Cannot find account to send bugreport, local path: "
+                    + bugreportPath);
         }
     }
 
@@ -109,11 +111,11 @@
         final Intent intent = new Intent(Intent.ACTION_SEND);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.setType("application/octet-stream");
-        intent.putExtra("subject", bugreportUri.getLastPathSegment());
+        intent.putExtra(Intent.EXTRA_SUBJECT, bugreportUri.getLastPathSegment());
         final StringBuilder sb = new StringBuilder();
         sb.append(SystemProperties.get("ro.build.description"));
         sb.append("\n(Sent from BugMailer)");
-        intent.putExtra("body", sb.toString());
+        intent.putExtra(Intent.EXTRA_TEXT, (CharSequence)sb);
         if (screenshotUri != null) {
             final ArrayList<Uri> attachments = new ArrayList<Uri>();
             attachments.add(bugreportUri);
@@ -124,9 +126,10 @@
             intent.putExtra(Intent.EXTRA_STREAM, bugreportUri);
         }
         if (sendToAccount != null) {
-            intent.putExtra("to", sendToAccount.name);
+            intent.putExtra(Intent.EXTRA_EMAIL, new String[]{sendToAccount.name});
+            return intent;
         }
-        return intent;
+        return null;
     }
 
     private Account findSendToAccount() {
@@ -134,6 +137,10 @@
                 .getService(Context.ACCOUNT_SERVICE));
         Account[] accounts = null;
         Account foundAccount = null;
+        String preferredDomain = SystemProperties.get("sendbug.preferred.domain");
+        if (!preferredDomain.startsWith("@")) {
+            preferredDomain = "@" + preferredDomain;
+        }
         try {
             accounts = accountManager.getAccounts(null);
         } catch (RemoteException e) {
@@ -141,13 +148,20 @@
         }
         if (accounts != null) {
             for (Account account : accounts) {
-                if (GOOGLE_ACCOUNT_TYPE.equals(account.type)) {
-                    // return first gmail account found
-                    return account;
-                } else if (EMAIL_ACCOUNT_TYPE.equals(account.type)) {
-                    // keep regular email account for now in case there are gmail accounts
-                    // found later
-                    foundAccount = account;
+                if (EMAIL_REGEX.matcher(account.name).matches()) {
+                    if (!preferredDomain.isEmpty()) {
+                        // if we have a preferred domain and it matches, return; otherwise keep
+                        // looking
+                        if (account.name.endsWith(preferredDomain)) {
+                            return account;
+                        } else {
+                            foundAccount = account;
+                        }
+                        // if we don't have a preferred domain, just return since it looks like
+                        // an email address
+                    } else {
+                        return account;
+                    }
                 }
             }
         }
diff --git a/tests/ext4/android_emmc_perf_tests.sh b/tests/ext4/android_emmc_perf_tests.sh
index 23190f8..202c095 100755
--- a/tests/ext4/android_emmc_perf_tests.sh
+++ b/tests/ext4/android_emmc_perf_tests.sh
@@ -7,11 +7,6 @@
   echo "Cannot read $PERF test binary"
 fi
 
-if [ ! -r "$PERF_OSYNC" ]
-then
-  echo "Cannot read $PERF_OSYNC test binary"
-fi
-
 if ! adb shell true >/dev/null 2>&1
 then
   echo "No device detected over adb"
@@ -49,6 +44,11 @@
     CACHE="/dev/block/platform/sdhci-tegra.3/by-name/CAC"
     ;;
 
+  manta)
+    CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+    CACHE="/dev/block/platform/dw_mmc.0/by-name/cache"
+    ;;
+
   *)
     echo "Unknown hardware $HARDWARE.  Exiting."
     exit 1
@@ -58,7 +58,6 @@
 adb root
 adb wait-for-device
 adb push "$PERF" /dev
-adb push "$PERF_OSYNC" /dev
 adb shell stop
 adb shell stop sdcard
 adb shell stop ril-daemon
@@ -99,6 +98,7 @@
 # Random read test
 for I in 1 2 3
 do
+  adb shell "echo 3 > /proc/sys/vm/drop_caches"
   echo "Random read test $I"
   adb shell /dev/"$PERF" -r 100 "$CACHE"
 done
@@ -114,7 +114,7 @@
 for I in 1 2 3
 do
   echo "Random write with o_sync test $I"
-  adb shell /dev/"$PERF" -w 100 -o "$CACHE"
+  adb shell /dev/"$PERF" -w -o 100 "$CACHE"
 done
 
 # Make a new empty /cache filesystem
diff --git a/tests/sdcard/sdcard_perf_test.cpp b/tests/sdcard/sdcard_perf_test.cpp
index 28069b9..c93c52b 100644
--- a/tests/sdcard/sdcard_perf_test.cpp
+++ b/tests/sdcard/sdcard_perf_test.cpp
@@ -37,13 +37,14 @@
 #include <sys/stat.h>
 #include <linux/fadvise.h>
 #include <unistd.h>
+#include <fts.h>
 
 #include "stopwatch.h"
 #include "sysutil.h"
 #include "testcase.h"
 
 // Stress test for the sdcard. Use this to generate some load on the
-// sdcard and collect performance statistics. The ouput is either a
+// sdcard and collect performance statistics. The output is either a
 // human readable report or the raw timing samples that can be
 // processed using another tool.
 //
@@ -109,6 +110,7 @@
 struct option long_options[] = {
     {"size", required_argument, 0, 's'},
     {"chunk-size", required_argument, 0, 'S'},
+    {"depth", required_argument, 0, 'D'},
     {"iterations",  required_argument, 0, 'i'},
     {"procnb",  required_argument, 0, 'p'},
     {"test",  required_argument, 0, 't'},
@@ -125,11 +127,12 @@
 
 void usage()
 {
-    printf("sdcard_perf_test --test=write|read|read_write|open_create [options]\n\n"
+    printf("sdcard_perf_test --test=write|read|read_write|open_create|traverse [options]\n\n"
            "  -t --test:        Select the test.\n"
            "  -s --size:        Size in kbytes of the data.\n"
            "  -S --chunk-size:  Size of a chunk. Default to size ie 1 chunk.\n"
            "                    Data will be written/read using that chunk size.\n"
+           "  -D --depth:       Depth of directory tree to create for traversal.\n",
            "  -i --iterations:  Number of time a process should carry its task.\n"
            "  -p --procnb:      Number of processes to use.\n"
            "  -d --dump:        Print the raw timing on stdout.\n"
@@ -208,7 +211,7 @@
         int option_index = 0;
 
         c = getopt_long (argc, argv,
-                         "hS:s:i:p:t:dcf:ezZa:",
+                         "hS:s:D:i:p:t:dcf:ezZa:",
                          long_options,
                          &option_index);
         // Detect the end of the options.
@@ -222,6 +225,9 @@
             case 'S':
                 testCase->setChunkSize(atoi(optarg) * 1024);
                 break;
+            case 'D': // tree depth
+                testCase->setTreeDepth(atoi(optarg));
+                break;
             case 'i':
                 testCase->setIter(atoi(optarg));
                 printf("# Iterations: %d\n", testCase->iter());
@@ -367,7 +373,7 @@
         char filename[80] = {'\0',};
 
         sprintf(filename, "%s/file-%d-%d", kTestDir, i, testCase->pid());
-        int fd = open(filename, O_RDWR | O_CREAT);
+        int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU);
 
         size_t left = size;
         while (left > 0)
@@ -414,7 +420,7 @@
 
     sprintf(filename, "%s/file-%d-%d", kTestDir, idx, getpid());
     testCase->openTimer()->start();
-    int fd = open(filename, O_RDWR | O_CREAT);  // no O_TRUNC, see header comment
+    int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU);  // no O_TRUNC, see header comment
     testCase->openTimer()->stop();
 
     if (fd < 0)
@@ -533,7 +539,7 @@
     {
         sprintf(filename, "%s/file-%d-%d", kTestDir, i, testCase->pid());
 
-        int fd = open(filename, O_RDWR | O_CREAT);
+        int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU);
         FADVISE(fd, 0, 0, testCase->fadvise());
 
         if (testCase->truncateToSize())
@@ -550,6 +556,127 @@
     return true;
 }
 
+bool writeTestFile(TestCase *testCase, const char* filename) {
+    int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU);
+    if (fd < 0) {
+        fprintf(stderr, "open() failed: %s\n", strerror(errno));
+        return false;
+    }
+
+    bool res = false;
+
+    char * const chunk = new char[testCase->chunkSize()];
+    memset(chunk, 0xaa, testCase->chunkSize());
+
+    size_t left = testCase->dataSize();
+    while (left > 0) {
+        char *dest = chunk;
+        size_t chunk_size = testCase->chunkSize();
+
+        if (chunk_size > left) {
+            chunk_size = left;
+            left = 0;
+        } else {
+            left -= chunk_size;
+        }
+
+        while (chunk_size > 0) {
+            ssize_t s = write(fd, dest, chunk_size);
+            if (s < 0) {
+                fprintf(stderr, "write() failed: %s\n", strerror(errno));
+                goto fail;
+            }
+            chunk_size -= s;
+            dest += s;
+        }
+    }
+
+    res = true;
+fail:
+    close(fd);
+    delete[] chunk;
+    return res;
+}
+
+// ----------------------------------------------------------------------
+// TRAVERSE
+
+#define MAX_PATH 512
+
+// Creates a directory tree that is both deep and wide, and times
+// traversal using fts_open().
+bool testTraverse(TestCase *testCase) {
+    char path[MAX_PATH];
+    char filepath[MAX_PATH];
+    strcpy(path, kTestDir);
+
+    // Generate a deep directory hierarchy
+    size_t depth = testCase->treeDepth();
+    for (size_t i = 0; i < depth; i++) {
+        // Go deeper by appending onto current path
+        snprintf(path + strlen(path), MAX_PATH - strlen(path), "/dir%d", i);
+        mkdir(path, S_IRWXU);
+
+        // Create some files at this depth
+        strcpy(filepath, path);
+        int pathlen = strlen(path);
+        char* nameStart = filepath + pathlen;
+        for (size_t j = 0; j < depth; j++) {
+            snprintf(nameStart, MAX_PATH - pathlen, "/file%d", j);
+            writeTestFile(testCase, filepath);
+        }
+    }
+
+    testCase->signalParentAndWait();
+    testCase->testTimer()->start();
+
+    // Now traverse structure
+    size_t iter = testCase->iter();
+    for (size_t i = 0; i < iter; i++) {
+        testCase->traverseTimer()->start();
+
+        FTS *ftsp;
+        if ((ftsp = fts_open((char **) &kTestDir, FTS_LOGICAL | FTS_XDEV, NULL)) == NULL) {
+            fprintf(stderr, "fts_open() failed: %s\n", strerror(errno));
+            return false;
+        }
+
+        // Count discovered files
+        int dirs = 0, files = 0;
+
+        FTSENT *curr;
+        while ((curr = fts_read(ftsp)) != NULL) {
+            switch (curr->fts_info) {
+            case FTS_D:
+                dirs++;
+                break;
+            case FTS_F:
+                files++;
+                break;
+            }
+        }
+
+        fts_close(ftsp);
+
+        testCase->traverseTimer()->stop();
+
+        int expectedDirs = depth + 1;
+        if (expectedDirs != dirs) {
+            fprintf(stderr, "expected %d dirs, but found %d\n", expectedDirs, dirs);
+            return false;
+        }
+
+        int expectedFiles = depth * depth;
+        if (expectedFiles != files) {
+            fprintf(stderr, "expected %d files, but found %d\n", expectedFiles, files);
+            return false;
+        }
+    }
+
+    testCase->testTimer()->stop();
+    return true;
+}
+
 }  // anonymous namespace
 
 int main(int argc, char **argv)
@@ -583,6 +710,9 @@
         case TestCase::READ_WRITE:
             testCase.mTestBody = testReadWrite;
             break;
+        case TestCase::TRAVERSE:
+            testCase.mTestBody = testTraverse;
+            break;
         default:
             fprintf(stderr, "Unknown test type %s", testCase.name());
             exit(EXIT_FAILURE);
diff --git a/tests/sdcard/testcase.cpp b/tests/sdcard/testcase.cpp
index 0de436f..06fd71b 100644
--- a/tests/sdcard/testcase.cpp
+++ b/tests/sdcard/testcase.cpp
@@ -41,7 +41,7 @@
 
 TestCase::TestCase(const char *appName)
     : mTestBody(NULL), mAppName(appName), mDataSize(1000 * 1000),
-      mChunkSize(mDataSize), mIter(20), mNproc(1),
+      mChunkSize(mDataSize), mTreeDepth(8), mIter(20), mNproc(1),
       mType(UNKNOWN_TEST),  mDump(false), mCpuScaling(false),
       mSync(NO_SYNC), mFadvice(POSIX_FADV_NORMAL), mTruncateToSize(false),
       mTestTimer(NULL)
@@ -105,6 +105,7 @@
             if(writeTimer()->used()) writeTimer()->sprint(&str, &size_left);
             if(syncTimer()->used()) syncTimer()->sprint(&str, &size_left);
             if(truncateTimer()->used()) truncateTimer()->sprint(&str, &size_left);
+            if(traverseTimer()->used()) traverseTimer()->sprint(&str, &size_left);
 
             write(mIpc[TestCase::WRITE_TO_PARENT], buffer, str - buffer);
 
@@ -163,6 +164,8 @@
     mSyncTimer = new StopWatch("sync", iter());
 
     mTruncateTimer = new StopWatch("truncate", iter());
+
+    mTraverseTimer = new StopWatch("traversal", iter());
 }
 
 bool TestCase::setTypeFromName(const char *test_name)
@@ -172,6 +175,7 @@
     if (strcmp(mName, "read") == 0) mType = READ;
     if (strcmp(mName, "read_write") == 0) mType = READ_WRITE;
     if (strcmp(mName, "open_create") == 0) mType = OPEN_CREATE;
+    if (strcmp(mName, "traverse") == 0) mType = TRAVERSE;
 
     return UNKNOWN_TEST != mType;
 }
diff --git a/tests/sdcard/testcase.h b/tests/sdcard/testcase.h
index 66af9d6..e973d9a 100644
--- a/tests/sdcard/testcase.h
+++ b/tests/sdcard/testcase.h
@@ -41,7 +41,7 @@
 
 class TestCase {
   public:
-    enum Type {UNKNOWN_TEST, WRITE, READ, OPEN_CREATE, READ_WRITE};
+    enum Type {UNKNOWN_TEST, WRITE, READ, OPEN_CREATE, READ_WRITE, TRAVERSE};
     enum Pipe {READ_FROM_CHILD = 0, WRITE_TO_PARENT, READ_FROM_PARENT, WRITE_TO_CHILD};
     enum Sync {NO_SYNC, FSYNC, SYNC};
 
@@ -66,6 +66,9 @@
     size_t chunkSize() const { return mChunkSize; }
     void setChunkSize(size_t val) { mChunkSize = val; }
 
+    size_t treeDepth() const { return mTreeDepth; }
+    void setTreeDepth(size_t val) { mTreeDepth = val; }
+
     bool newFairSleepers() const { return mNewFairSleepers; }
     void setNewFairSleepers(bool val) {
         mNewFairSleepers = val;
@@ -101,6 +104,7 @@
     StopWatch *writeTimer() { return mWriteTimer; }
     StopWatch *syncTimer() { return mSyncTimer; }
     StopWatch *truncateTimer() { return mTruncateTimer; }
+    StopWatch *traverseTimer() { return mTraverseTimer; }
 
     // Fork the children, run the test and wait for them to complete.
     bool runTest();
@@ -125,6 +129,7 @@
     const char *mAppName;
     size_t mDataSize;
     size_t mChunkSize;
+    size_t mTreeDepth;
     size_t mIter;
     size_t mNproc;
     pid_t mPid;
@@ -156,6 +161,7 @@
     StopWatch *mWriteTimer;  // Used to time the write calls.
     StopWatch *mSyncTimer;  // Used to time the sync/fsync calls.
     StopWatch *mTruncateTimer;  // Used to time the ftruncate calls.
+    StopWatch *mTraverseTimer;  // Used to time each traversal.
 };
 
 }  // namespace android_test