Project import
diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/tests/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/tests/NOTICE b/tests/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/tests/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/tests/audio/Android.mk b/tests/audio/Android.mk
new file mode 100644
index 0000000..f69a2fc
--- /dev/null
+++ b/tests/audio/Android.mk
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/tests/audio/alsa/Android.mk b/tests/audio/alsa/Android.mk
new file mode 100644
index 0000000..c6e5a8a
--- /dev/null
+++ b/tests/audio/alsa/Android.mk
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := pcmtest
+LOCAL_SRC_FILES := pcmtest.cpp
+LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libtinyalsa
+LOCAL_STATIC_LIBRARIES += libtestUtil
+LOCAL_C_INCLUDES += system/extras/tests/include external/tinyalsa/include
+
+include $(BUILD_NATIVE_TEST)
diff --git a/tests/audio/alsa/pcmtest.cpp b/tests/audio/alsa/pcmtest.cpp
new file mode 100644
index 0000000..7233e10
--- /dev/null
+++ b/tests/audio/alsa/pcmtest.cpp
@@ -0,0 +1,224 @@
+/*
+ * 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 requied 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.
+ *
+ */
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <gtest/gtest.h>
+#include <linux/ioctl.h>
+#define __force
+#define __bitwise
+#define __user
+#include <sound/asound.h>
+#include <sys/types.h>
+#include <tinyalsa/asoundlib.h>
+
+#define LOG_TAG "pcmtest"
+#include <utils/Log.h>
+#include <testUtil.h>
+
+#define PCM_PREFIX	"pcm"
+#define MIXER_PREFIX	"control"
+#define TIMER_PREFIX	"timer"
+
+const char kSoundDir[] = "/dev/snd";
+
+typedef struct PCM_NODE {
+    unsigned int card;
+    unsigned int device;
+    unsigned int flags;
+} pcm_node_t;
+
+static pcm_node_t *pcmnodes;
+
+static unsigned int pcms;
+static unsigned int cards;
+static unsigned int mixers;
+static unsigned int timers;
+
+unsigned int getPcmNodes(void)
+{
+    DIR *d;
+    struct dirent *de;
+    unsigned int pcount = 0;
+
+    d = opendir(kSoundDir);
+    if (d == 0)
+        return 0;
+    while ((de = readdir(d)) != NULL) {
+        if (de->d_name[0] == '.')
+            continue;
+        if (strstr(de->d_name, PCM_PREFIX))
+            pcount++;
+    }
+    closedir(d);
+    return pcount;
+}
+
+int getSndDev(unsigned int pcmdevs)
+{
+    DIR *d;
+    struct dirent *de;
+    unsigned int prevcard = -1;
+
+    d = opendir(kSoundDir);
+    if (d == 0)
+        return -ENXIO;
+    pcmnodes = (pcm_node_t *)malloc(pcmdevs * sizeof(pcm_node_t));
+    if (!pcmnodes)
+        return -ENOMEM;
+    pcms = 0;
+    while ((de = readdir(d)) != NULL) {
+        if (de->d_name[0] == '.')
+            continue;
+        /* printf("%s\n", de->d_name); */
+        if (strstr(de->d_name, PCM_PREFIX)) {
+            char flags;
+
+            EXPECT_LE(pcms, pcmdevs) << "Too many PCMs";
+            if (pcms >= pcmdevs)
+                continue;
+            sscanf(de->d_name, PCM_PREFIX "C%uD%u", &(pcmnodes[pcms].card),
+                   &(pcmnodes[pcms].device));
+            flags = de->d_name[strlen(de->d_name)-1];
+            if (flags == 'c') {
+                pcmnodes[pcms].flags = PCM_IN;
+            } else if(flags == 'p') {
+                pcmnodes[pcms].flags = PCM_OUT;
+            } else {
+                pcmnodes[pcms].flags = -1;
+                testPrintI("Unknown PCM type = %c", flags);
+            }
+            if (prevcard != pcmnodes[pcms].card)
+                cards++;
+            prevcard = pcmnodes[pcms].card;
+            pcms++;
+            continue;
+        }
+        if (strstr(de->d_name, MIXER_PREFIX)) {
+            unsigned int mixer = -1;
+            sscanf(de->d_name, MIXER_PREFIX "C%u", &mixer);
+            mixers++;
+            continue;
+        }
+        if (strstr(de->d_name, TIMER_PREFIX)) {
+            timers++;
+            continue;
+        }
+    }
+    closedir(d);
+    return 0;
+}
+
+int getPcmParams(unsigned int i)
+{
+    struct pcm_params *params;
+    unsigned int min;
+    unsigned int max;
+
+    params = pcm_params_get(pcmnodes[i].card, pcmnodes[i].device,
+                            pcmnodes[i].flags);
+    if (params == NULL)
+        return -ENODEV;
+
+    min = pcm_params_get_min(params, PCM_PARAM_RATE);
+    max = pcm_params_get_max(params, PCM_PARAM_RATE);
+    EXPECT_LE(min, max);
+    /* printf("        Rate:\tmin=%uHz\tmax=%uHz\n", min, max); */
+    min = pcm_params_get_min(params, PCM_PARAM_CHANNELS);
+    max = pcm_params_get_max(params, PCM_PARAM_CHANNELS);
+    EXPECT_LE(min, max);
+    /* printf("    Channels:\tmin=%u\t\tmax=%u\n", min, max); */
+    min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS);
+    max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS);
+    EXPECT_LE(min, max);
+    /* printf(" Sample bits:\tmin=%u\t\tmax=%u\n", min, max); */
+    min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE);
+    max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE);
+    EXPECT_LE(min, max);
+    /* printf(" Period size:\tmin=%u\t\tmax=%u\n", min, max); */
+    min = pcm_params_get_min(params, PCM_PARAM_PERIODS);
+    max = pcm_params_get_max(params, PCM_PARAM_PERIODS);
+    EXPECT_LE(min, max);
+    /* printf("Period count:\tmin=%u\t\tmax=%u\n", min, max); */
+
+    pcm_params_free(params);
+    return 0;
+}
+
+TEST(pcmtest, CheckAudioDir) {
+    pcms = getPcmNodes();
+    ASSERT_GT(pcms, 0U);
+}
+
+TEST(pcmtest, GetSoundDevs) {
+    int err = getSndDev(pcms);
+    testPrintI(" DEVICES = PCMS:%u CARDS:%u MIXERS:%u TIMERS:%u",
+               pcms, cards, mixers, timers);
+    ASSERT_EQ(0, err);
+}
+
+TEST(pcmtest, CheckPcmSanity0) {
+    ASSERT_NE(0U, pcms);
+}
+
+TEST(pcmtest, CheckPcmSanity1) {
+    EXPECT_NE(1U, pcms % 2);
+}
+
+TEST(pcmtests, CheckMixerSanity) {
+    ASSERT_NE(0U, mixers);
+    ASSERT_EQ(mixers, cards);
+}
+
+TEST(pcmtest, CheckTimesSanity0) {
+    ASSERT_NE(0U, timers);
+}
+
+TEST(pcmtest, CheckTimesSanity1) {
+    EXPECT_EQ(1U, timers);
+}
+
+TEST(pcmtest, CheckPcmDevices) {
+    for (unsigned int i = 0; i < pcms; i++) {
+        EXPECT_EQ(0, getPcmParams(i));
+    }
+    free(pcmnodes);
+}
+
+TEST(pcmtest, CheckMixerDevices) {
+    struct mixer *mixer;
+    for (unsigned int i = 0; i < mixers; i++) {
+         mixer = mixer_open(i);
+         EXPECT_TRUE(mixer != NULL);
+         if (mixer)
+             mixer_close(mixer);
+    }
+}
+
+TEST(pcmtest, CheckTimer) {
+    int ver = 0;
+    int fd = open("/dev/snd/timer", O_RDWR | O_NONBLOCK);
+    ASSERT_GE(fd, 0);
+    int ret = ioctl(fd, SNDRV_TIMER_IOCTL_PVERSION, &ver);
+    EXPECT_EQ(0, ret);
+    testPrintI(" Timer Version = 0x%x", ver);
+    close(fd);
+}
diff --git a/tests/binder/Android.mk b/tests/binder/Android.mk
new file mode 100644
index 0000000..4343259
--- /dev/null
+++ b/tests/binder/Android.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2010 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.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/tests/binder/benchmarks/Android.mk b/tests/binder/benchmarks/Android.mk
new file mode 100644
index 0000000..eb2ead2
--- /dev/null
+++ b/tests/binder/benchmarks/Android.mk
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2010 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_MODULE_TAGS := eng tests
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativebenchmark
+
+LOCAL_STATIC_LIBRARIES += \
+    libtestUtil
+
+LOCAL_SHARED_LIBRARIES += \
+    libutils \
+    liblog \
+    libbinder
+
+LOCAL_C_INCLUDES += \
+    system/extras/tests/include \
+    frameworks/base/include
+
+LOCAL_MODULE := binderAddInts
+LOCAL_SRC_FILES := binderAddInts.cpp
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/binder/benchmarks/binderAddInts.cpp b/tests/binder/benchmarks/binderAddInts.cpp
new file mode 100644
index 0000000..f061f7c
--- /dev/null
+++ b/tests/binder/benchmarks/binderAddInts.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2010 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.
+ *
+ */
+
+/*
+ * Binder add integers benchmark
+ *
+ * Measures the rate at which a short binder IPC operation can be
+ * performed.  The operation consists of the client sending a parcel
+ * that contains two integers.  For each parcel that the server
+ * receives, it adds the two integers and sends the sum back to
+ * the client.
+ *
+ * This benchmark supports the following command-line options:
+ *
+ *   -c cpu - bind client to specified cpu (default: unbound)
+ *   -s cpu - bind server to specified cpu (default: unbound)
+ *   -n num - perform IPC operation num times (default: 1000)
+ *   -d time - delay specified amount of seconds after each
+ *             IPC operation. (default 1e-3)
+ */
+
+#include <cerrno>
+#include <grp.h>
+#include <iostream>
+#include <libgen.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+#include <testUtil.h>
+
+using namespace android;
+using namespace std;
+
+const int unbound = -1; // Indicator for a thread not bound to a specific CPU
+
+String16 serviceName("test.binderAddInts");
+
+struct options {
+    int serverCPU;
+    int clientCPU;
+    unsigned int iterations;
+    float        iterDelay; // End of iteration delay in seconds
+} options = { // Set defaults
+    unbound, // Server CPU
+    unbound, // Client CPU
+    1000,    // Iterations
+    1e-3,    // End of iteration delay
+};
+
+class AddIntsService : public BBinder
+{
+  public:
+    explicit AddIntsService(int cpu = unbound);
+    virtual ~AddIntsService() {}
+
+    enum command {
+        ADD_INTS = 0x120,
+    };
+
+    virtual status_t onTransact(uint32_t code,
+                                const Parcel& data, Parcel* reply,
+                                uint32_t flags = 0);
+
+  private:
+    int cpu_;
+};
+
+// File scope function prototypes
+static void server(void);
+static void client(void);
+static void bindCPU(unsigned int cpu);
+static ostream &operator<<(ostream &stream, const String16& str);
+static ostream &operator<<(ostream &stream, const cpu_set_t& set);
+
+int main(int argc, char *argv[])
+{
+    int rv;
+
+    // Determine CPUs available for use.
+    // This testcase limits its self to using CPUs that were
+    // available at the start of the benchmark.
+    cpu_set_t availCPUs;
+    if ((rv = sched_getaffinity(0, sizeof(availCPUs), &availCPUs)) != 0) {
+        cerr << "sched_getaffinity failure, rv: " << rv
+            << " errno: " << errno << endl;
+        exit(1);
+    }
+
+    // Parse command line arguments
+    int opt;
+    while ((opt = getopt(argc, argv, "s:c:n:d:?")) != -1) {
+        char *chptr; // character pointer for command-line parsing
+
+        switch (opt) {
+        case 'c': // client CPU
+        case 's': { // server CPU
+            // Parse the CPU number
+            int cpu = strtoul(optarg, &chptr, 10);
+            if (*chptr != '\0') {
+                cerr << "Invalid cpu specified for -" << (char) opt
+                    << " option of: " << optarg << endl;
+                exit(2);
+            }
+
+            // Is the CPU available?
+            if (!CPU_ISSET(cpu, &availCPUs)) {
+                cerr << "CPU " << optarg << " not currently available" << endl;
+                cerr << "  Available CPUs: " << availCPUs << endl;
+                exit(3);
+            }
+
+            // Record the choice
+            *((opt == 'c') ? &options.clientCPU : &options.serverCPU) = cpu;
+            break;
+        }
+
+        case 'n': // iterations
+            options.iterations = strtoul(optarg, &chptr, 10);
+            if (*chptr != '\0') {
+                cerr << "Invalid iterations specified of: " << optarg << endl;
+                exit(4);
+            }
+            if (options.iterations < 1) {
+                cerr << "Less than 1 iteration specified by: "
+                    << optarg << endl;
+                exit(5);
+            }
+            break;
+
+        case 'd': // Delay between each iteration
+            options.iterDelay = strtod(optarg, &chptr);
+            if ((*chptr != '\0') || (options.iterDelay < 0.0)) {
+                cerr << "Invalid delay specified of: " << optarg << endl;
+                exit(6);
+            }
+            break;
+
+        case '?':
+        default:
+            cerr << basename(argv[0]) << " [options]" << endl;
+            cerr << "  options:" << endl;
+            cerr << "    -s cpu - server CPU number" << endl;
+            cerr << "    -c cpu - client CPU number" << endl;
+            cerr << "    -n num - iterations" << endl;
+            cerr << "    -d time - delay after operation in seconds" << endl;
+            exit(((optopt == 0) || (optopt == '?')) ? 0 : 7);
+        }
+    }
+
+    // Display selected options
+    cout << "serverCPU: ";
+    if (options.serverCPU == unbound) {
+        cout << " unbound";
+    } else {
+        cout << options.serverCPU;
+    }
+    cout << endl;
+    cout << "clientCPU: ";
+    if (options.clientCPU == unbound) {
+        cout << " unbound";
+    } else {
+        cout << options.clientCPU;
+    }
+    cout << endl;
+    cout << "iterations: " << options.iterations << endl;
+    cout << "iterDelay: " << options.iterDelay << endl;
+
+    // Fork client, use this process as server
+    fflush(stdout);
+    switch (pid_t pid = fork()) {
+    case 0: // Child
+        client();
+        return 0;
+
+    default: // Parent
+        server();
+
+        // Wait for all children to end
+        do {
+            int stat;
+            rv = wait(&stat);
+            if ((rv == -1) && (errno == ECHILD)) { break; }
+            if (rv == -1) {
+                cerr << "wait failed, rv: " << rv << " errno: "
+                    << errno << endl;
+                perror(NULL);
+                exit(8);
+            }
+        } while (1);
+        return 0;
+
+    case -1: // Error
+        exit(9);
+    }
+
+    return 0;
+}
+
+static void server(void)
+{
+    int rv;
+
+    // Add the service
+    sp<ProcessState> proc(ProcessState::self());
+    sp<IServiceManager> sm = defaultServiceManager();
+    if ((rv = sm->addService(serviceName,
+        new AddIntsService(options.serverCPU))) != 0) {
+        cerr << "addService " << serviceName << " failed, rv: " << rv
+            << " errno: " << errno << endl;
+    }
+
+    // Start threads to handle server work
+    proc->startThreadPool();
+}
+
+static void client(void)
+{
+    int rv;
+    sp<IServiceManager> sm = defaultServiceManager();
+    double min = FLT_MAX, max = 0.0, total = 0.0; // Time in seconds for all
+                                                  // the IPC calls.
+
+    // If needed bind to client CPU
+    if (options.clientCPU != unbound) { bindCPU(options.clientCPU); }
+
+    // Attach to service
+    sp<IBinder> binder;
+    do {
+        binder = sm->getService(serviceName);
+        if (binder != 0) break;
+        cout << serviceName << " not published, waiting..." << endl;
+        usleep(500000); // 0.5 s
+    } while(true);
+
+    // Perform the IPC operations
+    for (unsigned int iter = 0; iter < options.iterations; iter++) {
+        Parcel send, reply;
+
+        // Create parcel to be sent.  Will use the iteration cound
+        // and the iteration count + 3 as the two integer values
+        // to be sent.
+        int val1 = iter;
+        int val2 = iter + 3;
+        int expected = val1 + val2;  // Expect to get the sum back
+        send.writeInt32(val1);
+        send.writeInt32(val2);
+
+        // Send the parcel, while timing how long it takes for
+        // the answer to return.
+        struct timespec start;
+        clock_gettime(CLOCK_MONOTONIC, &start);
+        if ((rv = binder->transact(AddIntsService::ADD_INTS,
+            send, &reply)) != 0) {
+            cerr << "binder->transact failed, rv: " << rv
+                << " errno: " << errno << endl;
+            exit(10);
+        }
+        struct timespec current;
+        clock_gettime(CLOCK_MONOTONIC, &current);
+
+        // Calculate how long this operation took and update the stats
+        struct timespec deltaTimespec = tsDelta(&start, &current);
+        double delta = ts2double(&deltaTimespec);
+        min = (delta < min) ? delta : min;
+        max = (delta > max) ? delta : max;
+        total += delta;
+        int result = reply.readInt32();
+        if (result != (int) (iter + iter + 3)) {
+            cerr << "Unexpected result for iteration " << iter << endl;
+            cerr << "  result: " << result << endl;
+            cerr << "expected: " << expected << endl;
+        }
+
+        if (options.iterDelay > 0.0) { testDelaySpin(options.iterDelay); }
+    }
+
+    // Display the results
+    cout << "Time per iteration min: " << min
+        << " avg: " << (total / options.iterations)
+        << " max: " << max
+        << endl;
+}
+
+AddIntsService::AddIntsService(int cpu): cpu_(cpu) {
+    if (cpu != unbound) { bindCPU(cpu); }
+}
+
+// Server function that handles parcels received from the client
+status_t AddIntsService::onTransact(uint32_t code, const Parcel &data,
+                                    Parcel* reply, uint32_t /* flags */) {
+    int val1, val2;
+    status_t rv(0);
+    int cpu;
+
+    // If server bound to a particular CPU, check that
+    // were executing on that CPU.
+    if (cpu_ != unbound) {
+        cpu = sched_getcpu();
+        if (cpu != cpu_) {
+            cerr << "server onTransact on CPU " << cpu << " expected CPU "
+                  << cpu_ << endl;
+            exit(20);
+        }
+    }
+
+    // Perform the requested operation
+    switch (code) {
+    case ADD_INTS:
+        val1 = data.readInt32();
+        val2 = data.readInt32();
+        reply->writeInt32(val1 + val2);
+        break;
+
+    default:
+      cerr << "server onTransact unknown code, code: " << code << endl;
+      exit(21);
+    }
+
+    return rv;
+}
+
+static void bindCPU(unsigned int cpu)
+{
+    int rv;
+    cpu_set_t cpuset;
+
+    CPU_ZERO(&cpuset);
+    CPU_SET(cpu, &cpuset);
+    rv = sched_setaffinity(0, sizeof(cpuset), &cpuset);
+
+    if (rv != 0) {
+        cerr << "bindCPU failed, rv: " << rv << " errno: " << errno << endl;
+        perror(NULL);
+        exit(30);
+    }
+}
+
+static ostream &operator<<(ostream &stream, const String16& str)
+{
+    for (unsigned int n1 = 0; n1 < str.size(); n1++) {
+        if ((str[n1] > 0x20) && (str[n1] < 0x80)) {
+            stream << (char) str[n1];
+        } else {
+            stream << '~';
+        }
+    }
+
+    return stream;
+}
+
+static ostream &operator<<(ostream &stream, const cpu_set_t& set)
+{
+    for (unsigned int n1 = 0; n1 < CPU_SETSIZE; n1++) {
+        if (CPU_ISSET(n1, &set)) {
+            if (n1 != 0) { stream << ' '; }
+            stream << n1;
+        }
+    }
+
+    return stream;
+}
diff --git a/tests/bootloader/bootctl.py b/tests/bootloader/bootctl.py
new file mode 100644
index 0000000..7a69a8c
--- /dev/null
+++ b/tests/bootloader/bootctl.py
@@ -0,0 +1,61 @@
+# Copyright (C) 2016 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.
+
+class Bootctl(object):
+    def __init__(self, device):
+        self.device = device
+        self.base = ["bootctl"]
+
+    def _exec(self, cmd):
+        return self.device.shell_nocheck(self.base + [cmd])
+
+    def get_number_slots(self):
+        """returns number of slots"""
+
+        return int(self._exec("get-number-slots")[1])
+
+    def get_current_slot(self):
+        """returns current slot number"""
+
+        return int(self._exec("get-current-slot")[1])
+
+    def mark_boot_successful(self):
+        """returns true on success, false on failure"""
+
+        return self._exec("mark-boot-successful")[0] == 0
+
+    def set_active_boot_slot(self, slot):
+        """returns true on success, false on failure"""
+
+        return self._exec("set-active-boot-slot " + str(slot))[0] == 0
+
+    def set_slot_as_unbootable_slot(self, slot):
+        """returns true on success, false on failure"""
+
+        return self._exec("set-slot-as-unbootable " + str(slot))[0] == 0
+
+    def is_slot_bootable(self, slot):
+        """Returns true if slot is bootable"""
+
+        return self._exec("is-slot-bootable " + str(slot))[0] == 0
+
+    def is_slot_marked_successful(self, slot):
+        """returns true on success, false on failure"""
+
+        return self._exec("is-slot-marked-successful " + str(slot))[0] == 0
+
+    def get_suffix(self, slot):
+        """returns suffix string for specified slot number"""
+
+        return self._exec("get-suffix " + str(slot))[1].strip()
diff --git a/tests/bootloader/haltest.py b/tests/bootloader/haltest.py
new file mode 100644
index 0000000..41252c3
--- /dev/null
+++ b/tests/bootloader/haltest.py
@@ -0,0 +1,116 @@
+# Copyright (C) 2016 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.
+
+import bootctl
+import shelltest
+import sys
+import unittest
+
+# Note: In order to run these tests, the device must be able to boot
+# from all slots on the device.
+class HalTest(shelltest.ShellTest):
+    def __init__(self, *args, **kwargs):
+        super(HalTest, self).__init__(*args, **kwargs)
+        self.bootctl = bootctl.Bootctl(self.device)
+
+    def test_slots(self):
+        """Test that all slots are reported and named uniquely."""
+
+        self.device.root()
+        self.device.wait()
+        num_slots = self.bootctl.get_number_slots()
+        suffixes = dict()
+        for slot in range(num_slots):
+            suffix = self.bootctl.get_suffix(slot)
+            self.assertNotEqual(suffix, "(null)")
+            suffixes[suffix] = slot
+        self.assertEqual(len(suffixes), num_slots)
+
+    def test_mark_successful(self):
+        """Ensure mark successful works, and persists on reboot.
+
+        Ensure that mark_successful will mark the slot as
+        successful, and that the HAL sees this. First resets
+        slot-successful by setting the active slot to the current one."""
+
+        self.device.root()
+        self.device.wait()
+        slot = self.bootctl.get_current_slot()
+        self.assertTrue(self.bootctl.set_active_boot_slot(slot))
+        self.assertFalse(self.bootctl.is_slot_marked_successful(slot))
+        self.assertTrue(self.bootctl.mark_boot_successful())
+        self.assertTrue(self.bootctl.is_slot_marked_successful(slot))
+        self.device.reboot()
+        self.device.wait()
+        self.device.root()
+        self.device.wait()
+        self.assertTrue(self.bootctl.is_slot_marked_successful(slot))
+
+    def test_switch_slots(self):
+        """Test that setActiveBootSlot works and persists
+
+        Ensure switching slots works, and that setting the slot does not
+        change the reported slot until the reboot."""
+
+        # Cycle through all slots once
+        num_slots = self.bootctl.get_number_slots()
+        for i in range(num_slots):
+            self.device.root()
+            self.device.wait()
+            slot = self.bootctl.get_current_slot()
+            new_slot = (slot + 1) % num_slots
+            self.assertTrue(self.bootctl.set_active_boot_slot(new_slot))
+            slot2 = self.bootctl.get_current_slot()
+            self.assertEqual(slot, slot2)
+            self.device.reboot()
+            self.device.wait()
+            self.device.root()
+            self.device.wait()
+            self.assertEqual(new_slot, self.bootctl.get_current_slot())
+
+    def test_unbootable(self):
+        """Test setSlotAsUnbootable
+
+        Test that the device will attempt to roll back to a valid slot if
+        the current slot is unbootable."""
+
+        # Cycle through all slots once
+        num_slots = self.bootctl.get_number_slots()
+        for i in range(num_slots):
+            self.device.root()
+            self.device.wait()
+            slot = self.bootctl.get_current_slot()
+            new_slot = (slot + 1) % num_slots
+            self.device.root()
+            self.device.wait()
+            self.assertTrue(self.bootctl.set_active_boot_slot(new_slot))
+            self.assertTrue(self.bootctl.is_slot_bootable(new_slot))
+            self.assertTrue(self.bootctl.set_slot_as_unbootable_slot(new_slot))
+            self.assertFalse(self.bootctl.is_slot_bootable(new_slot))
+            self.device.reboot()
+            self.device.wait()
+            self.device.root()
+            self.device.wait()
+            self.assertEqual(slot, self.bootctl.get_current_slot())
+            self.assertFalse(self.bootctl.is_slot_bootable(new_slot))
+            self.assertTrue(self.bootctl.set_active_boot_slot(new_slot))
+            self.assertTrue(self.bootctl.is_slot_bootable(new_slot))
+            self.device.reboot()
+            self.device.wait()
+            self.device.root()
+            self.device.wait()
+            self.assertEqual(new_slot, self.bootctl.get_current_slot());
+
+if __name__ == '__main__':
+    unittest.main(verbosity=3)
diff --git a/tests/bootloader/shelltest.py b/tests/bootloader/shelltest.py
new file mode 100644
index 0000000..d9fbba1
--- /dev/null
+++ b/tests/bootloader/shelltest.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2016 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.
+
+import adb
+import os
+import unittest
+
+class ShellTest(unittest.TestCase):
+    def __init__(self, *args, **kwargs):
+        super(ShellTest, self).__init__(*args, **kwargs)
+        self.device = adb.get_device(os.getenv("BOOTLOADER_TEST_SERIAL"));
diff --git a/tests/cpueater/Android.mk b/tests/cpueater/Android.mk
new file mode 100644
index 0000000..0bb08d9
--- /dev/null
+++ b/tests/cpueater/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2008 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.
+# Copyright The Android Open Source Project
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := cpueater
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_SRC_FILES := cpueater.c
+LOCAL_CFLAGS := -Wno-unused-parameter
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := daemonize
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_SRC_FILES := daemonize.c
+LOCAL_SHARED_LIBRARIES := libhardware_legacy
+include $(BUILD_EXECUTABLE)
+
diff --git a/tests/cpueater/NOTICE b/tests/cpueater/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/tests/cpueater/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/tests/cpueater/cpueater.c b/tests/cpueater/cpueater.c
new file mode 100644
index 0000000..c791139
--- /dev/null
+++ b/tests/cpueater/cpueater.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 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.
+ *
+ * Simple cpu eater busy loop. Runs as a daemon. prints the child PID to
+ * std so you can easily kill it later.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+int main(int argc, char *argv[])
+{
+    pid_t pid;
+    int life_universe_and_everything;
+    int fd;
+
+    switch(fork()) {
+        case -1:
+            perror(argv[0]);
+            exit(1);
+            break;
+        case 0: /* child */
+            chdir("/");
+            umask(0);
+            setpgrp();
+            setsid();
+            /* fork again to fully detach from controlling terminal. */
+            switch(pid = fork()) { 
+                case -1:
+                    break;
+                case 0: /* second child */
+                    /* redirect to /dev/null */
+                    close(0); 
+                    open("/dev/null", 0);
+                    close(1);
+                    if(open("/dev/null", O_WRONLY) < 0) {
+                        perror("/dev/null");
+                        exit(1);
+                    }
+                    fflush(stdout);
+                    close(2); 
+                    dup(1);
+                    for (fd = 3; fd < 256; fd++) {
+                        close(fd);
+                    }
+                    /* busy looper */
+                    while (1) {
+                        life_universe_and_everything = 42 * 2;
+                    }
+                  default:
+                      /* so caller can easily kill it later. */
+                      printf("%d\n", pid);
+                      exit(0);
+                      break;
+                }
+                break;
+          default:
+              exit(0);
+              break;
+    }
+  return 0;
+}
+
+
+/* vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab */
+
diff --git a/tests/cpueater/daemonize.c b/tests/cpueater/daemonize.c
new file mode 100644
index 0000000..e9b39b5
--- /dev/null
+++ b/tests/cpueater/daemonize.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2008 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.
+ *
+ */
+
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+
+#include "hardware_legacy/power.h"
+
+
+int main(int argc, char **argv)
+{
+  int pid, fd, mode;
+  unsigned int delay = 0;
+  int status = 0;
+  char *file = 0;
+  char lockid[32];
+
+  if (argc < 2) { 
+    printf("Usage: %s [-f logfile] [-a] [-d delay] <program>\n", argv[0]);
+    exit(1);
+  }
+  close(0); open("/dev/null", 0);
+  close(1);
+
+  mode = O_TRUNC;
+
+  while(**++argv == '-') {
+    while(*++*argv) {
+      switch(**argv) {
+        case 'f':
+          if(*++*argv)
+            file = *argv;
+          else
+            file = *++argv;
+          goto next_arg;
+        case 'd':
+          if(*++*argv)
+            delay = atoi(*argv);
+          else
+            delay = atoi(*++argv);
+          goto next_arg;
+        case 'a':
+          mode = O_APPEND;
+          break;
+      }
+    }
+next_arg: ;
+  }
+
+  if (file) {
+      if(open(file, O_WRONLY|mode|O_CREAT, 0666) < 0) {
+        perror(file);
+        exit(1);
+      }
+  }
+  else {
+      if(open("/dev/null", O_WRONLY) < 0) {
+        perror("/dev/null");
+        exit(1);
+      }
+  }
+
+  switch(pid = fork()) {
+    case -1:
+      perror(argv[0]);
+      exit(1);
+      break;
+    case 0:
+      fflush(stdout);
+      close(2); dup(1); /* join stdout and stderr */
+      chdir("/");
+      umask(0);
+      setpgrp();
+      setsid();
+      for (fd = 3; fd < 256; fd++) {
+          close(fd);
+      }
+      if(delay) {
+          snprintf(lockid, 32, "daemonize%d", (int) getpid());
+          acquire_wake_lock(PARTIAL_WAKE_LOCK, lockid);
+      }
+
+      switch(pid = fork()) {
+        case -1:
+          break;
+        case 0:
+          if(delay) {
+              sleep(delay);
+          }
+          execv(argv[0], argv);
+          execvp(argv[0], argv);
+          perror(argv[0]);
+          break;
+        default:
+          if(delay) {
+              waitpid(pid, &status, 0);
+              release_wake_lock(lockid);
+          }
+          _exit(0);
+      }
+      _exit(1);
+      break;
+    default:
+      exit(0);
+      break;
+  }
+}
+
+/* vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab */
diff --git a/tests/crypto/Android.mk b/tests/crypto/Android.mk
new file mode 100644
index 0000000..e118e5d
--- /dev/null
+++ b/tests/crypto/Android.mk
@@ -0,0 +1,11 @@
+# Copyright 2013 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= get_dm_versions.c
+LOCAL_MODULE:= get_dm_versions
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wno-unused-parameter
+include $(BUILD_EXECUTABLE)
diff --git a/tests/crypto/get_dm_versions.c b/tests/crypto/get_dm_versions.c
new file mode 100644
index 0000000..8ffe0a1
--- /dev/null
+++ b/tests/crypto/get_dm_versions.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/dm-ioctl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define DM_CRYPT_BUF_SIZE 4096
+
+static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
+{
+    memset(io, 0, dataSize);
+    io->data_size = dataSize;
+    io->data_start = sizeof(struct dm_ioctl);
+    io->version[0] = 4;
+    io->version[1] = 0;
+    io->version[2] = 0;
+    io->flags = flags;
+    if (name) {
+        strncpy(io->name, name, sizeof(io->name));
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    char buffer[DM_CRYPT_BUF_SIZE];
+    struct dm_ioctl *io;
+    struct dm_target_versions *v;
+    int i;
+    int fd;
+
+    fd = open("/dev/device-mapper", O_RDWR);
+    if (fd < 0) {
+        fprintf(stderr, "Cannot open /dev/device-mapper\n");
+        exit(1);
+    }
+
+    io = (struct dm_ioctl *) buffer;
+
+    ioctl_init(io, DM_CRYPT_BUF_SIZE, NULL, 0);
+
+    if (ioctl(fd, DM_LIST_VERSIONS, io)) {
+        fprintf(stderr, "ioctl(DM_LIST_VERSIONS) returned an error\n");
+        exit(1);
+    }
+
+    /* Iterate over the returned versions, and print each subsystem's version */
+    v = (struct dm_target_versions *) &buffer[sizeof(struct dm_ioctl)];
+    while (v->next) {
+        printf("%s: %d.%d.%d\n", v->name, v->version[0], v->version[1], v->version[2]);
+        v = (struct dm_target_versions *)(((char *)v) + v->next);
+    }
+
+    close(fd);
+    exit(0);
+}
+
diff --git a/tests/directiotest/Android.mk b/tests/directiotest/Android.mk
new file mode 100644
index 0000000..fb5f12a
--- /dev/null
+++ b/tests/directiotest/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := directiotest
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_SRC_FILES := directiotest.c
+include $(BUILD_EXECUTABLE)
diff --git a/tests/directiotest/directiotest.c b/tests/directiotest/directiotest.c
new file mode 100644
index 0000000..6ed8bda
--- /dev/null
+++ b/tests/directiotest/directiotest.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2010 by Garmin Ltd. or its subsidiaries
+ *
+ * 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.
+ *
+ * Performs a simple write/readback test to verify correct functionality
+ * of direct i/o on a block device node.
+ */
+
+/* For large-file support */
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+/* For O_DIRECT */
+#define _GNU_SOURCE
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/fs.h>
+
+#define NUM_TEST_BLKS 128
+
+/*
+ * Allocate page-aligned memory.  Could use posix_memalign(3), but some
+ * systems don't support it.  Also pre-faults memory since we'll be using
+ * it all right away anyway.
+ */
+static void *pagealign_alloc(size_t size)
+{
+	void *ret = mmap(NULL, size, PROT_READ | PROT_WRITE,
+			MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_LOCKED,
+			-1, 0);
+	if (ret == MAP_FAILED) {
+		perror("mmap");
+		ret = NULL;
+	}
+	return ret;
+}
+
+static void pagealign_free(void *addr, size_t size)
+{
+	int ret = munmap(addr, size);
+	if (ret == -1)
+		perror("munmap");
+}
+
+static ssize_t do_read(int fd, void *buf, off64_t start, size_t count)
+{
+	ssize_t ret;
+	size_t bytes_read = 0;
+
+	lseek64(fd, start, SEEK_SET);
+
+	do {
+		ret = read(fd, (char *)buf + bytes_read, count - bytes_read);
+		if (ret == -1) {
+			perror("read");
+			return -1;
+		} else if (ret == 0) {
+			fprintf(stderr, "Unexpected end-of-file\n");
+			return -1;
+		}
+		bytes_read += ret;
+	} while (bytes_read < count);
+
+	return bytes_read;
+}
+
+static ssize_t do_write(int fd, const void *buf, off64_t start, size_t count)
+{
+	ssize_t ret;
+	size_t bytes_out = 0;
+
+	lseek64(fd, start, SEEK_SET);
+
+	do {
+		ret = write(fd, (char *)buf + bytes_out, count - bytes_out);
+		if (ret == -1) {
+			perror("write");
+			return -1;
+		} else if (ret == 0) {
+			fprintf(stderr, "write returned 0\n");
+			return -1;
+		}
+		bytes_out += ret;
+	} while (bytes_out < count);
+
+	return bytes_out;
+}
+
+/*
+ * Initializes test buffer with locally-unique test pattern.  High 16-bits of
+ * each 32-bit word contain first disk block number of the test area, low
+ * 16-bits contain word offset into test area.  The goal is that a given test
+ * area should never contain the same data as a nearby test area, and that the
+ * data for a given test area be easily reproducable given the start block and
+ * test area size.
+ */
+static void init_test_buf(void *buf, uint64_t start_blk, size_t len)
+{
+	uint32_t *data = buf;
+	size_t i;
+
+	len /= sizeof(uint32_t);
+	for (i = 0; i < len; i++)
+		data[i] = (start_blk & 0xFFFF) << 16 | (i & 0xFFFF);
+}
+
+static void dump_hex(const void *buf, int len)
+{
+	const uint8_t *data = buf;
+	int i;
+	char ascii_buf[17];
+
+	ascii_buf[16] = '\0';
+
+	for (i = 0; i < len; i++) {
+		int val = data[i];
+		int off = i % 16;
+
+		if (off == 0)
+			printf("%08x  ", i);
+		printf("%02x ", val);
+		ascii_buf[off] = isprint(val) ? val : '.';
+		if (off == 15)
+			printf(" %-16s\n", ascii_buf);
+	}
+
+	i %= 16;
+	if (i) {
+		ascii_buf[i] = '\0';
+		while (i++ < 16)
+			printf("   ");
+		printf(" %-16s\n", ascii_buf);
+	}
+}
+
+static void update_progress(int current, int total)
+{
+	double pct_done = (double)current * 100 / total;
+	printf("Testing area %d/%d (%6.2f%% complete)\r", current, total,
+			pct_done);
+	fflush(stdout);
+}
+
+int main(int argc, const char *argv[])
+{
+	int ret = 1;
+	const char *path;
+	int fd;
+	struct stat stat;
+	void *read_buf = NULL, *write_buf = NULL;
+	int blk_size;
+	uint64_t num_blks;
+	size_t test_size;
+	int test_areas, i;
+
+	if (argc != 2) {
+		printf("Usage: directiotest blkdev_path\n");
+		exit(1);
+	}
+
+	path = argv[1];
+	fd = open(path, O_RDWR | O_DIRECT | O_LARGEFILE);
+	if (fd == -1) {
+		perror("open");
+		exit(1);
+	}
+	if (fstat(fd, &stat) == -1) {
+		perror("stat");
+		goto cleanup;
+	} else if (!S_ISBLK(stat.st_mode)) {
+		fprintf(stderr, "%s is not a block device\n", path);
+		goto cleanup;
+	}
+
+	if (ioctl(fd, BLKSSZGET, &blk_size) == -1) {
+		perror("ioctl");
+		goto cleanup;
+	}
+	if (ioctl(fd, BLKGETSIZE64, &num_blks) == -1) {
+		perror("ioctl");
+		goto cleanup;
+	}
+	num_blks /= blk_size;
+
+	test_size = (size_t)blk_size * NUM_TEST_BLKS;
+	read_buf = pagealign_alloc(test_size);
+	write_buf = pagealign_alloc(test_size);
+	if (!read_buf || !write_buf) {
+		fprintf(stderr, "Error allocating test buffers\n");
+		goto cleanup;
+	}
+
+	/*
+	 * Start the actual test.  Go through the entire device, writing
+	 * locally-unique patern to each test block and then reading it
+	 * back.
+	 */
+	if (num_blks / NUM_TEST_BLKS > INT_MAX) {
+		printf("Warning: Device too large for test variables\n");
+		printf("Entire device will not be tested\n");
+		test_areas = INT_MAX;
+	} else {
+		test_areas = num_blks / NUM_TEST_BLKS;
+	}
+
+	printf("Starting test\n");
+
+	for (i = 0; i < test_areas; i++) {
+		uint64_t cur_blk = (uint64_t)i * NUM_TEST_BLKS;
+
+		update_progress(i + 1, test_areas);
+
+		init_test_buf(write_buf, cur_blk, test_size);
+
+		if (do_write(fd, write_buf, cur_blk * blk_size, test_size) !=
+				(ssize_t)test_size) {
+			fprintf(stderr, "write failed, aborting test\n");
+			goto cleanup;
+		}
+		if (do_read(fd, read_buf, cur_blk * blk_size, test_size) !=
+				(ssize_t)test_size) {
+			fprintf(stderr, "read failed, aborting test\n");
+			goto cleanup;
+		}
+
+		if (memcmp(write_buf, read_buf, test_size)) {
+			printf("Readback verification failed at block %" PRIu64 "\n\n",
+					cur_blk);
+			printf("Written data:\n");
+			dump_hex(write_buf, test_size);
+			printf("\nRead data:\n");
+			dump_hex(read_buf, test_size);
+			goto cleanup;
+		}
+	}
+
+	printf("\nTest complete\n");
+	ret = 0;
+
+cleanup:
+	if (read_buf)
+		pagealign_free(read_buf, test_size);
+	if (write_buf)
+		pagealign_free(write_buf, test_size);
+	close(fd);
+	return ret;
+}
diff --git a/tests/ext4/Android.mk b/tests/ext4/Android.mk
new file mode 100644
index 0000000..bdd4072
--- /dev/null
+++ b/tests/ext4/Android.mk
@@ -0,0 +1,18 @@
+# Copyright 2012 The Android Open Source Project
+
+local_target_dir := $(TARGET_OUT_DATA)/local/tmp
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= rand_emmc_perf.c
+LOCAL_MODULE:= rand_emmc_perf
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32:= rand_emmc_perf
+LOCAL_MODULE_STEM_64:= rand_emmc_perf64
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(local_target_dir)
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := libm libc
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/tests/ext4/android_emmc_perf_tests.sh b/tests/ext4/android_emmc_perf_tests.sh
new file mode 100755
index 0000000..6464312
--- /dev/null
+++ b/tests/ext4/android_emmc_perf_tests.sh
@@ -0,0 +1,284 @@
+#!/bin/bash
+
+PERF="rand_emmc_perf"
+PERF_LOC=/dev
+STATS_FILE="/data/local/tmp/stats_test"
+STATS_MODE=0
+USERBUILD_MODE=0
+
+if [ "$1" = "-s" ]
+then
+  STATS_MODE=1
+elif [ "$1" = "-u" ]
+then
+  USERBUILD_MODE=1
+fi
+
+if [ ! -r "$PERF" ]
+then
+  echo "Cannot read $PERF test binary"
+fi
+
+if ! adb shell true >/dev/null 2>&1
+then
+  echo "No device detected over adb"
+fi
+
+HARDWARE=`adb shell getprop ro.hardware | tr -d "\r"`
+
+case "$HARDWARE" in
+  tuna | steelhead)
+    CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+    CACHE="/dev/block/platform/omap/omap_hsmmc.0/by-name/cache"
+    MMCDEV="mmcblk0"
+    ;;
+
+  stingray | wingray)
+    CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+    CACHE="/dev/block/platform/sdhci-tegra.3/by-name/cache"
+    MMCDEV="mmcblk0"
+    ;;
+
+  herring)
+    echo "This test will wipe the userdata partition on $HARDWARE devices."
+    read -p "Do you want to proceed? " ANSWER
+
+    if [ "$ANSWER" != "yes" ]
+    then
+      echo "aborting test"
+      exit 1
+    fi
+
+    CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+    CACHE="/dev/block/platform/s3c-sdhci.0/by-name/userdata"
+    MMCDEV="mmcblk0"
+    ;;
+
+  grouper)
+    CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+    CACHE="/dev/block/platform/sdhci-tegra.3/by-name/CAC"
+    MMCDEV="mmcblk0"
+    ;;
+
+  manta)
+    CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+    CACHE="/dev/block/platform/dw_mmc.0/by-name/cache"
+    MMCDEV="mmcblk0"
+    ;;
+
+  flo)
+    CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+    CACHE="dev/block/platform/msm_sdcc.1/by-name/cache"
+    MMCDEV="mmcblk0"
+    ;;
+
+  *)
+    echo "Unknown hardware $HARDWARE.  Exiting."
+    exit 1
+esac
+
+# We cannot stop and unmount stuff in a user build, so don't even try.
+if [ "$USERBUILD_MODE" -eq 0 ]
+then
+  # prepare the device
+  adb root
+  adb wait-for-device
+  adb push "$PERF" /dev
+  adb shell stop
+  adb shell stop sdcard
+  adb shell stop ril-daemon
+  adb shell stop media
+  adb shell stop drm
+  adb shell stop keystore
+  adb shell stop tf_daemon
+  adb shell stop bluetoothd
+  adb shell stop hciattach
+  adb shell stop p2p_supplicant
+  adb shell stop wpa_supplicant
+  adb shell stop mobicore
+  adb shell umount /sdcard >/dev/null 2>&1
+  adb shell umount /mnt/sdcard >/dev/null 2>&1
+  adb shell umount /mnt/shell/sdcard0 >/dev/null 2>&1
+  adb shell umount /mnt/shell/emulated >/dev/null 2>&1
+  adb shell umount /cache >/dev/null 2>&1
+  if [ "$STATS_MODE" -ne 1 ]
+  then
+    adb shell umount /data >/dev/null 2>&1
+  fi
+else
+  # For user builds, put the $PERF binary in /data/local/tmp,
+  # and also setup CACHE to point to a file on /data/local/tmp,
+  # and create that file
+  PERF_LOC=/data/local/tmp
+  adb push "$PERF" "$PERF_LOC"
+  CACHE=/data/local/tmp/testfile
+  echo "Creating testfile for user builds (can take up to 60 seconds)"
+  adb shell dd if=/dev/zero of=$CACHE bs=1048576 count=512
+fi
+
+# Add more services here that other devices need to stop.
+# So far, this list is sufficient for:
+#   Prime
+
+if [ "$USERBUILD_MODE" -eq 0 ]
+then
+  # At this point, the device is quiescent, need to crank up the cpu speed,
+  # then run tests
+  adb shell "cat $CPUFREQ/cpuinfo_max_freq > $CPUFREQ/scaling_max_freq"
+  adb shell "cat $CPUFREQ/cpuinfo_max_freq > $CPUFREQ/scaling_min_freq"
+fi
+
+# Start the tests
+
+if [ "$STATS_MODE" -eq 1 ]
+then
+  # This test looks for the average and max random write times for the emmc
+  # chip.  It should be run with the emmc chip full for worst case numbers,
+  # and after fstrim for best case numbers.  So first fill the chip, twice,
+  # then run the test, then remove the large file, run fstrim, and run the
+  # test again.
+
+  # Remove the test file if it exists, then make it anew.
+  echo "Filling userdata"
+  adb shell rm  -f "$STATS_FILE"
+  adb shell dd if=/dev/zero of="$STATS_FILE" bs=1048576
+  adb shell sync
+
+  # Do it again to make sure to fill up all the reserved blocks used for
+  # wear levelling, plus any unused blocks in the other partitions.  Yes,
+  # this is not precise, just a good heuristic.
+  echo "Filling userdata again"
+  adb shell rm "$STATS_FILE"
+  adb shell sync
+  adb shell dd if=/dev/zero of="$STATS_FILE" bs=1048576
+  adb shell sync
+
+  # Run the test
+  echo "Running stats test after filling emmc chip"
+  adb shell /dev/$PERF -w -o -s 20000 -f /dev/full_stats 400 "$CACHE"
+
+  # Remove the file, and have vold do fstrim
+  adb shell rm "$STATS_FILE"
+  adb shell sync
+  # Make sure fstrim knows there is work to do
+  sleep 10
+
+  # Get the current number of FSTRIM complete lines in thh logcat
+  ORIGCNT=`adb shell logcat -d | grep -c "Finished fstrim work"`
+
+  # Attempt to start fstrim
+  OUT=`adb shell vdc fstrim dotrim | grep "Command not recognized"`
+
+  if [ -z "$OUT" ]
+  then
+    # Wait till we see another fstrim finished line
+    sleep 10
+    let T=10
+    NEWCNT=`adb shell logcat -d |grep -c "Finished fstrim work"`
+    while [ "$NEWCNT" -eq "$ORIGCNT" ]
+    do
+      sleep 10
+      let T=T+10
+      if [ "$T" -ge 300 ]
+      then
+        echo "Error: FSTRIM did not complete in 300 seconds, continuing"
+        break
+      fi
+      NEWCNT=`adb shell logcat -d |grep -c "Finished fstrim work"`
+    done
+
+    echo "FSTRIM took "$T" seconds"
+
+    # Run the test again
+    echo "Running test after fstrim"
+    adb shell /dev/$PERF -w -o -s 20000 -f /dev/fstrimmed_stats 400 "$CACHE"
+
+    # Retrieve the full data logs
+    adb pull /dev/fstrimmed_stats $HARDWARE-fstrimmed_stats
+    adb pull /dev/full_stats $HARDWARE-full_stats
+  else
+    echo "Device doesn't support fstrim, not running test a second time"
+  fi
+
+else
+
+  # Sequential read test
+  if [ "$USERBUILD_MODE" -eq 0 ]
+  then
+    # There is no point in running this in USERBUILD mode, because
+    # we can't drop caches, and the numbers are ludicrously high
+    for I in 1 2 3
+    do
+      adb shell "echo 3 > /proc/sys/vm/drop_caches"
+      echo "Sequential read test $I"
+      adb shell dd if="$CACHE" of=/dev/null bs=1048576 count=200
+    done
+  fi
+
+  # Sequential write test
+  for I in 1 2 3
+  do
+    echo "Sequential write test $I"
+    # It's unclear if this test is useful on USERBUILDS, given the
+    # caching on the filesystem
+    adb shell dd if=/dev/zero conv=notrunc of="$CACHE" bs=1048576 count=200
+  done
+
+  if [ "$USERBUILD_MODE" -eq 0 ]
+  then
+    # Random read tests require that we read from a much larger range of offsets
+    # into the emmc chip than the write test.  If we only read though 100 Megabytes
+    # (and with a read-ahead of 128K), we quickly fill the buffer cache with 100
+    # Megabytes of data, and subsequent reads are nearly instantaneous.  Since
+    # reading is non-destructive, and we've never shipped a device with less than
+    # 8 Gbytes, for this test we read from the raw emmc device, and randomly seek
+    # in the first 6 Gbytes.  That is way more memory than any device we currently
+    # have and it should keep the cache from being poluted with entries from
+    # previous random reads.
+    #
+    # Also, test with the read-ahead set very low at 4K, and at the default
+
+    # Random read test, 4K read-ahead
+    ORIG_READAHEAD=`adb shell cat /sys/block/$MMCDEV/queue/read_ahead_kb | tr -d "\r"`
+    adb shell "echo 4 > /sys/block/$MMCDEV/queue/read_ahead_kb"
+    for I in 1 2 3
+    do
+      adb shell "echo 3 > /proc/sys/vm/drop_caches"
+      echo "Random read (4K read-ahead) test $I"
+      adb shell "$PERF_LOC"/"$PERF" -r 6000 "/dev/block/$MMCDEV"
+    done
+
+    # Random read test, default read-ahead
+    adb shell "echo $ORIG_READAHEAD > /sys/block/$MMCDEV/queue/read_ahead_kb"
+    for I in 1 2 3
+    do
+      adb shell "echo 3 > /proc/sys/vm/drop_caches"
+      echo "Random read (default read-ahead of ${ORIG_READAHEAD}K) test $I"
+      adb shell "$PERF_LOC"/"$PERF" -r 6000 "/dev/block/$MMCDEV"
+    done
+  fi
+
+  # Random write test
+  for I in 1 2 3
+  do
+    echo "Random write test $I"
+    adb shell "$PERF_LOC"/"$PERF" -w 100 "$CACHE"
+  done
+
+  # Random write test with O_SYNC
+  for I in 1 2 3
+  do
+    echo "Random write with o_sync test $I"
+    adb shell "$PERF_LOC"/"$PERF" -w -o 100 "$CACHE"
+  done
+fi
+
+# cleanup
+if [ "$USERBUILD_MODE" -eq 0 ]
+then
+  # Make a new empty /cache filesystem
+  adb shell make_ext4fs -w "$CACHE"
+else
+  adb shell rm -f "$CACHE" "$PERF_LOC"/"$PERF"
+fi
+
diff --git a/tests/ext4/rand_emmc_perf.c b/tests/ext4/rand_emmc_perf.c
new file mode 100644
index 0000000..fed7a54
--- /dev/null
+++ b/tests/ext4/rand_emmc_perf.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+/* A simple test of emmc random read and write performance.  When testing write
+ * performance, try it twice, once with O_SYNC compiled in, and once with it commented
+ * out.  Without O_SYNC, the close(2) blocks until all the dirty buffers are written
+ * out, but the numbers tend to be higher.
+ */
+
+#define _LARGEFILE64_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+
+#define TST_BLK_SIZE 4096
+/* Number of seconds to run the test */
+#define TEST_LEN 10
+
+struct stats {
+    struct timeval start;
+    struct timeval end;
+    off64_t offset;
+};
+
+static void usage(void) {
+        fprintf(stderr, "Usage: rand_emmc_perf [ -r | -w ] [-o] [-s count] [-f full_stats_filename] <size_in_mb> <block_dev>\n");
+        exit(1);
+}
+
+static void print_stats(struct stats *stats_buf, int stats_count,
+                        char * full_stats_file)
+{
+    int i;
+    struct timeval t;
+    struct timeval sum = { 0, 0 };
+    struct timeval max = { 0, 0 };
+    long long total_usecs;
+    long long avg_usecs;
+    long long max_usecs;
+    long long variance = 0;;
+    long long x;
+    double sdev;
+    FILE *full_stats = NULL;
+
+    if (full_stats_file) {
+        full_stats = fopen(full_stats_file, "w");
+        if (full_stats == NULL) {
+            fprintf(stderr, "Cannot open full stats output file %s, ignoring\n",
+                    full_stats_file);
+        }
+    }
+
+    for (i = 0; i < stats_count; i++) {
+        timersub(&stats_buf[i].end, &stats_buf[i].start, &t);
+        if (timercmp(&t, &max, >)) {
+            max = t;
+        }
+        if (full_stats) {
+            fprintf(full_stats, "%lld\n", (t.tv_sec * 1000000LL) + t.tv_usec);
+        }
+        timeradd(&sum, &t, &sum);
+    }
+
+    if (full_stats) {
+        fclose(full_stats);
+    }
+
+    max_usecs = (max.tv_sec * 1000000LL) + max.tv_usec;
+    total_usecs = (sum.tv_sec * 1000000LL) + sum.tv_usec;
+    avg_usecs = total_usecs / stats_count;
+    printf("average random %d byte iop time = %lld usecs\n",
+           TST_BLK_SIZE, avg_usecs);
+    printf("maximum random %d byte iop time = %lld usecs\n",
+           TST_BLK_SIZE, max_usecs);
+
+    /* Now that we have the average (aka mean) go through the data
+     * again and compute the standard deviation.
+     * The formula is sqrt(sum_1_to_n((Xi - avg)^2)/n)
+     */
+    for (i = 0; i < stats_count; i++) {
+        timersub(&stats_buf[i].end, &stats_buf[i].start, &t);  /* Xi */
+        x = (t.tv_sec * 1000000LL) + t.tv_usec;                /* Convert to long long */
+        x = x - avg_usecs;                                     /* Xi - avg */
+        x = x * x;                                             /* (Xi - avg) ^ 2 */
+        variance += x;                                         /* Summation */
+    }
+    sdev = sqrt((double)variance/(double)stats_count);
+    printf("standard deviation of iops is %.2f\n", sdev);
+}
+
+static void stats_test(int fd, int write_mode, off64_t max_blocks, int stats_count,
+                       char *full_stats_file)
+{
+    struct stats *stats_buf;
+    char buf[TST_BLK_SIZE] = { 0 };
+    int i;
+
+    stats_buf = malloc(stats_count * sizeof(struct stats));
+    if (stats_buf == NULL) {
+        fprintf(stderr, "Cannot allocate stats_buf\n");
+        exit(1);
+    }
+
+    for (i = 0; i < stats_count; i++) {
+        gettimeofday(&stats_buf[i].start, NULL);
+
+        if (lseek64(fd, (rand() % max_blocks) * TST_BLK_SIZE, SEEK_SET) < 0) {
+            fprintf(stderr, "lseek64 failed\n");
+        }
+
+        if (write_mode) {
+            if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
+                fprintf(stderr, "Short write\n");
+            }
+        } else {
+            if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
+                fprintf(stderr, "Short read\n");
+            }
+        }
+
+        gettimeofday(&stats_buf[i].end, NULL);
+    }
+
+    print_stats(stats_buf, stats_count, full_stats_file);
+}
+
+static void perf_test(int fd, int write_mode, off64_t max_blocks)
+{
+    struct timeval start, end, res;
+    char buf[TST_BLK_SIZE] = { 0 };
+    long long iops = 0;
+    int msecs;
+
+    res.tv_sec = 0;
+    gettimeofday(&start, NULL);
+    while (res.tv_sec < TEST_LEN) {
+        if (lseek64(fd, (rand() % max_blocks) * TST_BLK_SIZE, SEEK_SET) < 0) {
+            fprintf(stderr, "lseek64 failed\n");
+        }
+        if (write_mode) {
+            if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
+                fprintf(stderr, "Short write\n");
+            }
+        } else {
+            if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
+                fprintf(stderr, "Short read\n");
+            }
+        }
+        iops++;
+        gettimeofday(&end, NULL);
+        timersub(&end, &start, &res);
+    }
+    close(fd);
+
+    /* The close can take a while when in write_mode as buffers are flushed.
+     * So get the time again. */
+    gettimeofday(&end, NULL);
+    timersub(&end, &start, &res);
+
+    msecs = (res.tv_sec * 1000) + (res.tv_usec / 1000);
+    printf("%.0f %dbyte iops/sec\n", (float)iops * 1000 / msecs, TST_BLK_SIZE);
+}
+
+int main(int argc, char *argv[])
+{
+    int fd, fd2;
+    int write_mode = 0;
+    int o_sync = 0;
+    int stats_mode = 0;
+    int stats_count;
+    char *full_stats_file = NULL;
+    off64_t max_blocks;
+    unsigned int seed;
+    int c;
+
+    while ((c = getopt(argc, argv, "+rwos:f:")) != -1) {
+        switch (c) {
+          case '?':
+          default:
+            usage();
+            break;
+
+          case 'r':
+            /* Do nothing, read mode is the default */
+            break;
+
+          case 'w':
+            write_mode = 1;
+            break;
+
+          case 'o':
+            o_sync = O_SYNC;
+            break;
+
+          case 's':
+            stats_mode = 1;
+            stats_count = atoi(optarg);
+            break;
+
+          case 'f':
+            free(full_stats_file);
+            full_stats_file = strdup(optarg);
+            if (full_stats_file == NULL) {
+                fprintf(stderr, "Cannot get full stats filename\n");
+            }
+            break;
+        }
+    }
+
+    if (o_sync && !write_mode) {
+        /* Can only specify o_sync in write mode.  Probably doesn't matter,
+         * but clear o_sync if in read mode */
+        o_sync = 0;
+    }
+
+    if ((argc - optind) != 2) {
+        usage();
+    }
+
+    /* Size is given in megabytes, so compute the number of TST_BLK_SIZE blocks. */
+    max_blocks = atoll(argv[optind]) * ((1024*1024) / TST_BLK_SIZE);
+
+    if ((fd = open(argv[optind + 1], O_RDWR | o_sync)) < 0) {
+        fprintf(stderr, "Cannot open block device %s\n", argv[optind + 1]);
+        exit(1);
+    }
+
+    fd2 = open("/dev/urandom", O_RDONLY);
+    if (fd2 < 0) {
+        fprintf(stderr, "Cannot open /dev/urandom\n");
+    }
+    if (read(fd2, &seed, sizeof(seed)) != sizeof(seed)) {
+        fprintf(stderr, "Cannot read /dev/urandom\n");
+    }
+    close(fd2);
+    srand(seed);
+
+    if (stats_mode) {
+        stats_test(fd, write_mode, max_blocks, stats_count, full_stats_file);
+    } else {
+        perf_test(fd, write_mode, max_blocks);
+    }
+    free(full_stats_file);
+
+    exit(0);
+}
+
diff --git a/tests/framebuffer/Android.mk b/tests/framebuffer/Android.mk
new file mode 100644
index 0000000..7f4c712
--- /dev/null
+++ b/tests/framebuffer/Android.mk
@@ -0,0 +1,24 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	refresh.c
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils
+
+LOCAL_MODULE:= test-fb-refresh
+
+LOCAL_CFLAGS := -Wno-unused-parameter
+
+include $(BUILD_EXECUTABLE)
+
+##
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := fb_test.c
+LOCAL_MODULE = test-fb-simple
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := libc
+LOCAL_CFLAGS := -Wno-unused-parameter
+include $(BUILD_EXECUTABLE)
diff --git a/tests/framebuffer/fb_test.c b/tests/framebuffer/fb_test.c
new file mode 100644
index 0000000..0b8bc68
--- /dev/null
+++ b/tests/framebuffer/fb_test.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <linux/fb.h>
+#include <linux/kd.h>
+
+struct simple_fb {
+    void *data;
+    int width;
+    int height;
+    int stride;
+    int bpp;
+};
+
+static struct simple_fb gr_fbs[2];
+static unsigned gr_active_fb = 0;
+
+static int gr_fb_fd = -1;
+static int gr_vt_fd = -1;
+
+static struct fb_var_screeninfo vi;
+struct fb_fix_screeninfo fi;
+struct timespec tv, tv2;
+
+static void dumpinfo(struct fb_fix_screeninfo *fi,
+                     struct fb_var_screeninfo *vi);
+
+static int get_framebuffer(struct simple_fb *fb, unsigned bpp)
+{
+    int fd;
+    void *bits;
+    int bytes_per_pixel;
+
+    fd = open("/dev/graphics/fb0", O_RDWR);
+    if (fd < 0) {
+        printf("cannot open /dev/graphics/fb0, retrying with /dev/fb0\n");
+        if ((fd = open("/dev/fb0", O_RDWR)) < 0) {
+            perror("cannot open /dev/fb0");
+            return -1;
+        }
+    }
+
+    if(ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
+        perror("failed to get fb0 info");
+        return -1;
+    }
+
+    if (bpp && vi.bits_per_pixel != bpp) {
+        printf("bpp != %d, forcing...\n", bpp);
+        vi.bits_per_pixel = bpp;
+        if(ioctl(fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
+            perror("failed to force bpp");
+            return -1;
+        }
+    }
+
+    if(ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
+        perror("failed to get fb0 info");
+        return -1;
+    }
+
+    dumpinfo(&fi, &vi);
+
+    bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    if(bits == MAP_FAILED) {
+        perror("failed to mmap framebuffer");
+        return -1;
+    }
+
+    bytes_per_pixel = vi.bits_per_pixel >> 3;
+
+    fb->width = vi.xres;
+    fb->height = vi.yres;
+    fb->stride = fi.line_length / bytes_per_pixel;
+    fb->data = bits;
+    fb->bpp = vi.bits_per_pixel;
+
+    fb++;
+
+    fb->width = vi.xres;
+    fb->height = vi.yres;
+    fb->stride = fi.line_length / bytes_per_pixel;
+    fb->data = (void *)((unsigned long)bits +
+                        vi.yres * vi.xres * bytes_per_pixel);
+    fb->bpp = vi.bits_per_pixel;
+
+    return fd;
+}
+
+static void set_active_framebuffer(unsigned n)
+{
+    if(n > 1) return;
+    vi.yres_virtual = vi.yres * 2;
+    vi.yoffset = n * vi.yres;
+    if(ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
+        fprintf(stderr,"active fb swap failed!\n");
+    } else
+        printf("active buffer: %d\n", n);
+}
+
+static void dumpinfo(struct fb_fix_screeninfo *fi, struct fb_var_screeninfo *vi)
+{
+    fprintf(stderr,"vi.xres = %d\n", vi->xres);
+    fprintf(stderr,"vi.yres = %d\n", vi->yres);
+    fprintf(stderr,"vi.xresv = %d\n", vi->xres_virtual);
+    fprintf(stderr,"vi.yresv = %d\n", vi->yres_virtual);
+    fprintf(stderr,"vi.xoff = %d\n", vi->xoffset);
+    fprintf(stderr,"vi.yoff = %d\n", vi->yoffset);
+    fprintf(stderr, "vi.bits_per_pixel = %d\n", vi->bits_per_pixel);
+
+    fprintf(stderr, "fi.line_length = %d\n", fi->line_length);
+
+}
+
+int gr_init(int bpp, int id)
+{
+    int fd = -1;
+
+    if (!access("/dev/tty0", F_OK)) {
+        fd = open("/dev/tty0", O_RDWR | O_SYNC);
+        if(fd < 0)
+            return -1;
+
+        if(ioctl(fd, KDSETMODE, (void*) KD_GRAPHICS)) {
+            close(fd);
+            return -1;
+        }
+    }
+
+    gr_fb_fd = get_framebuffer(gr_fbs, bpp);
+
+    if(gr_fb_fd < 0) {
+        if (fd >= 0) {
+            ioctl(fd, KDSETMODE, (void*) KD_TEXT);
+            close(fd);
+        }
+        return -1;
+    }
+
+    gr_vt_fd = fd;
+
+        /* start with 0 as front (displayed) and 1 as back (drawing) */
+    gr_active_fb = id;
+    set_active_framebuffer(id);
+
+    return 0;
+}
+
+void gr_exit(void)
+{
+    close(gr_fb_fd);
+    gr_fb_fd = -1;
+
+    if (gr_vt_fd >= 0) {
+        ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT);
+        close(gr_vt_fd);
+        gr_vt_fd = -1;
+    }
+}
+
+int gr_fb_width(void)
+{
+    return gr_fbs[0].width;
+}
+
+int gr_fb_height(void)
+{
+    return gr_fbs[0].height;
+}
+
+uint16_t red = 0xf800;
+uint16_t green = 0x07e0;
+uint16_t blue = 0x001f;
+uint16_t white = 0xffff;
+uint16_t black = 0x0;
+
+uint32_t red32 = 0x00ff0000;
+uint32_t green32 = 0x0000ff00;
+uint32_t blue32 = 0x000000ff;
+uint32_t white32 = 0x00ffffff;
+uint32_t black32 = 0x0;
+
+void draw_grid(int w, int h, void* _loc) {
+    int i, j;
+    int v;
+    int stride = fi.line_length / (vi.bits_per_pixel >> 3);
+    uint16_t *loc = _loc;
+    uint32_t *loc32 = _loc;
+
+    for (j = 0; j < h/2; j++) {
+        for (i = 0; i < w/2; i++)
+            if (vi.bits_per_pixel == 16)
+                loc[i + j*(stride)] = red;
+            else
+                loc32[i + j*(stride)] = red32;
+        for (; i < w; i++)
+            if (vi.bits_per_pixel == 16)
+                loc[i + j*(stride)] = green;
+            else
+                loc32[i + j*(stride)] = green32;
+    }
+
+    for (; j < h; j++) {
+        for (i = 0; i < w/2; i++)
+            if (vi.bits_per_pixel == 16)
+                loc[i + j*(stride)] = blue;
+            else
+                loc32[i + j*(stride)] = blue32;
+        for (; i < w; i++)
+            if (vi.bits_per_pixel == 16)
+                loc[i + j*(stride)] = white;
+            else
+                loc32[i + j*(stride)] = white32;
+    }
+
+}
+
+void clear_screen(int w, int h, void* _loc)
+{
+    int i,j;
+    int stride = fi.line_length / (vi.bits_per_pixel >> 3);
+    uint16_t *loc = _loc;
+    uint32_t *loc32 = _loc;
+
+    for (j = 0; j < h; j++)
+        for (i = 0; i < w; i++)
+            if (vi.bits_per_pixel == 16)
+                loc[i + j*(stride)] = black;
+            else
+                loc32[i + j*(stride)] = black32;
+}
+
+int main(int argc, char **argv) {
+  int w;
+  int h;
+  int id = 0;
+  int bpp = 0;
+
+  if (argc > 1)
+      bpp = atoi(argv[1]);
+
+  if (argc > 4)
+      id = !!atoi(argv[4]);
+
+  gr_init(bpp, id);
+
+  if (argc > 3) {
+      w = atoi(argv[2]);
+      h = atoi(argv[3]);
+  } else {
+      w = vi.xres;
+      h = vi.yres;
+  }
+
+  clear_screen(vi.xres, vi.yres, gr_fbs[0].data);
+  clear_screen(vi.xres, vi.yres, gr_fbs[1].data);
+
+  draw_grid(w, h, gr_fbs[id].data);
+
+  set_active_framebuffer(!id);
+  set_active_framebuffer(id);
+
+  return 0;
+}
diff --git a/tests/framebuffer/minui.h b/tests/framebuffer/minui.h
new file mode 100644
index 0000000..4efc971
--- /dev/null
+++ b/tests/framebuffer/minui.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 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 _MINUI_H_
+#define _MINUI_H_
+
+int gr_init(void);
+void gr_exit(void);
+
+int gr_fb_width(void);
+int gr_fb_height(void);
+void gr_flip(void);
+
+void gr_color(unsigned char r, unsigned char g, unsigned char b);
+void gr_fill(int x, int y, int w, int h);
+int gr_text(int x, int y, const char *s);
+int gr_measure(const char *s);
+
+
+typedef struct event event;
+
+struct event
+{
+    unsigned type;
+    unsigned code;
+    unsigned value;
+};
+    
+int ev_init(void);
+void ev_exit(void);
+
+int ev_get(event *ev, unsigned dont_wait);
+
+#define TYPE_KEY 1
+
+#define KEY_UP      103
+#define KEY_DOWN    108
+#define KEY_LEFT    105
+#define KEY_RIGHT   106
+#define KEY_CENTER  232
+#define KEY_ENTER   28
+
+#endif
diff --git a/tests/framebuffer/refresh.c b/tests/framebuffer/refresh.c
new file mode 100644
index 0000000..38e7871
--- /dev/null
+++ b/tests/framebuffer/refresh.c
@@ -0,0 +1,167 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#include <time.h>
+#include <errno.h>
+
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+
+#include <linux/fb.h>
+
+int64_t systemTime()
+{
+    struct timespec t;
+    t.tv_sec = t.tv_nsec = 0;
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    return (int64_t)(t.tv_sec)*1000000000LL + t.tv_nsec;
+}
+
+int main(int argc, char** argv)
+{
+    char const * const device_template[] = {
+            "/dev/graphics/fb%u",
+            "/dev/fb%u",
+            0 };
+    int fd = -1;
+    int i=0;
+    int j=0;
+    char name[64];
+    while ((fd==-1) && device_template[i]) {
+        snprintf(name, 64, device_template[i], 0);
+        fd = open(name, O_RDWR, 0);
+        i++;
+    }
+    if (fd < 0)
+        return -errno;
+        
+    struct fb_fix_screeninfo finfo;
+    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
+        return -errno;
+    
+    struct fb_var_screeninfo info;
+    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
+        return -errno;
+    
+    info.reserved[0] = 0;
+    info.reserved[1] = 0;
+    info.reserved[2] = 0;
+    info.xoffset = 0;
+    info.yoffset = 0;
+    info.bits_per_pixel = 16;
+    info.activate = FB_ACTIVATE_NOW;
+    
+    if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
+        printf("FBIOPUT_VSCREENINFO failed (%d x %d)\n",
+                info.xres_virtual, info.yres_virtual);
+        return 0;
+    }
+        
+    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
+        return -errno;    
+    
+    uint64_t denominator = (uint64_t)( info.upper_margin + info.lower_margin + info.yres )
+                         * ( info.left_margin  + info.right_margin + info.xres )
+                         * info.pixclock;
+    int refreshRate = denominator ? (1000000000000000LLU / denominator) : 0;
+    
+    float xdpi = (info.xres * 25.4f) / info.width; 
+    float ydpi = (info.yres * 25.4f) / info.height;
+    float fps  = refreshRate / 1000.0f; 
+    
+    printf( "using (fd=%d)\n"
+            "id           = %s\n"
+            "xres         = %d px\n"
+            "yres         = %d px\n"
+            "xres_virtual = %d px\n"
+            "yres_virtual = %d px\n"
+            "bpp          = %d\n"
+            "r            = %2u:%u\n"
+            "g            = %2u:%u\n"
+            "b            = %2u:%u\n",
+                fd,
+                finfo.id,
+                info.xres,
+                info.yres,
+                info.xres_virtual,
+                info.yres_virtual,
+                info.bits_per_pixel,
+                info.red.offset, info.red.length,
+                info.green.offset, info.green.length,
+                info.blue.offset, info.blue.length
+        );
+
+    printf( "width        = %d mm (%f dpi)\n"
+            "height       = %d mm (%f dpi)\n"
+            "refresh rate = %.2f Hz\n",
+                info.width,  xdpi,
+                info.height, ydpi,
+                fps
+        );
+    
+    printf("upper_margin=%d, lower_margin=%d, left_margin=%d, right_margin=%d, pixclock=%d, finfo.smem_len=%d\n",
+            info.upper_margin, info.lower_margin, info.left_margin, info.right_margin, info.pixclock, finfo.smem_len);
+
+    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
+        return -errno;
+    
+    if (finfo.smem_len <= 0)
+        return -errno;
+    
+    /*
+     * Open and map the display.
+     */
+    
+    uint16_t* buffer  = (uint16_t*) mmap(
+            0, finfo.smem_len,
+            PROT_READ | PROT_WRITE,
+            MAP_SHARED,
+            fd, 0);
+    
+    if (buffer == MAP_FAILED)
+        return -errno;
+    
+    // at least for now, always clear the fb
+    memset(buffer, 0, finfo.smem_len);
+    memset(buffer, 0xff, 320*(info.yres_virtual/2)*2);
+
+    int l,t,w,h;
+    l=0;
+    t=0;
+    w=320;
+    h=480;
+    info.reserved[0] = 0x54445055; // "UPDT";
+    info.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
+    info.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
+
+    int err;
+    int c = 0;
+    int64_t time = systemTime();
+    while (1) {
+        
+        info.activate = FB_ACTIVATE_VBL;
+        info.yoffset = 0;
+        ioctl(fd, FBIOPUT_VSCREENINFO, &info);
+
+        info.activate = FB_ACTIVATE_VBL;
+        info.yoffset = info.yres_virtual/2;
+        err = ioctl(fd, FBIOPUT_VSCREENINFO, &info);
+
+        c+=2;
+        if (c==60*2) {
+            int64_t now = systemTime();
+            time = now - time;
+            printf("refresh rate = %f Hz\n", (c*1000000000.0 / (double)time));
+            c = 0;
+            time = now;
+        }
+    }
+    return 0;
+}
diff --git a/tests/fstest/Android.mk b/tests/fstest/Android.mk
new file mode 100644
index 0000000..9be7ae4
--- /dev/null
+++ b/tests/fstest/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2008 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := recovery_test
+LOCAL_SRC_FILES := recovery_test.cpp
+LOCAL_SHARED_LIBRARIES += libcutils libutils liblog liblogwrap
+LOCAL_STATIC_LIBRARIES += libtestUtil libfs_mgr
+LOCAL_C_INCLUDES += system/extras/tests/include \
+                    system/extras/ext4_utils \
+                    system/core/logwrapper/include
+include $(BUILD_NATIVE_TEST)
diff --git a/tests/fstest/recovery_test.cpp b/tests/fstest/recovery_test.cpp
new file mode 100644
index 0000000..02c7e8f
--- /dev/null
+++ b/tests/fstest/recovery_test.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2014 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 requied 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.
+ *
+ */
+
+/*
+ * These file system recovery tests ensure the ability to recover from
+ * filesystem crashes in key blocks (e.g. superblock).
+ */
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fs_mgr.h>
+#include <gtest/gtest.h>
+#include <logwrap/logwrap.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "cutils/properties.h"
+#include "ext4.h"
+#include "ext4_utils.h"
+
+#define LOG_TAG "fsRecoveryTest"
+#include <utils/Log.h>
+#include <testUtil.h>
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define FSTAB_PREFIX "/fstab."
+#define SB_OFFSET 1024
+static char UMOUNT_BIN[] = "/system/bin/umount";
+static char VDC_BIN[] = "/system/bin/vdc";
+
+enum Fs_Type { FS_UNKNOWN, FS_EXT4, FS_F2FS };
+
+namespace android {
+
+class DataFileVerifier {
+ public:
+  explicit DataFileVerifier(const char* file_name) {
+    strncpy(test_file_, file_name, FILENAME_MAX);
+  }
+
+  void verify_write() {
+    int write_fd = open(test_file_, O_CREAT | O_WRONLY, 0666);
+    ASSERT_TRUE(write_fd);
+    ASSERT_EQ(write(write_fd, "TEST", 4), 4);
+    close(write_fd);
+  }
+
+  void verify_read() {
+    char read_buff[4];
+    int read_fd = open(test_file_, O_RDONLY);
+    ASSERT_TRUE(read_fd);
+    ASSERT_EQ(read(read_fd, read_buff, sizeof(read_buff)), 4);
+    ASSERT_FALSE(strncmp(read_buff, "TEST", 4));
+    close(read_fd);
+  }
+
+  ~DataFileVerifier() {
+    unlink(test_file_);
+  }
+
+ private:
+  char test_file_[FILENAME_MAX];
+};
+
+namespace ext4 {
+bool getSuperBlock(const int blk_fd, struct ext4_super_block* sb) {
+  if (lseek(blk_fd, SB_OFFSET, SEEK_SET) == -1) {
+    testPrintE("Cannot lseek to ext4 superblock to read");
+    return false;
+  }
+
+  if (read(blk_fd, sb, sizeof(*sb)) != sizeof(*sb)) {
+    testPrintE("Cannot read ext4 superblock");
+    return false;
+  }
+
+  if (sb->s_magic != 0xEF53) {
+    testPrintE("Invalid ext4 superblock magic");
+    return false;
+  }
+
+  return true;
+}
+
+bool setSbErrorBit(const int blk_fd) {
+  // Read super block.
+  struct ext4_super_block sb;
+  if (!getSuperBlock(blk_fd, &sb)) {
+    return false;
+  }
+
+  // Check that the detected errors bit is not set.
+  if (sb.s_state & 0x2) {
+    testPrintE("Ext4 superblock already corrupted");
+    return false;
+  }
+
+  // Set the detected errors bit.
+  sb.s_state |= 0x2;
+
+  // Write superblock.
+  if (lseek(blk_fd, SB_OFFSET, SEEK_SET) == -1) {
+      testPrintE("Cannot lseek to superblock to write\n");
+      return false;
+  }
+
+  if (write(blk_fd, &sb, sizeof(sb)) != sizeof(sb)) {
+      testPrintE("Cannot write superblock\n");
+      return false;
+  }
+
+  return true;
+}
+
+bool corruptGdtFreeBlock(const int blk_fd) {
+  // Read super block.
+  struct ext4_super_block sb;
+  if (!getSuperBlock(blk_fd, &sb)) {
+    return false;
+  }
+  // Make sure the block size is 2K or 4K.
+  if ((sb.s_log_block_size != 1) && (sb.s_log_block_size != 2)) {
+      testPrintE("Ext4 block size not 2K or 4K\n");
+      return false;
+  }
+  int block_size = 1 << (10 + sb.s_log_block_size);
+  int num_bgs = DIV_ROUND_UP(sb.s_blocks_count_lo, sb.s_blocks_per_group);
+
+  if (sb.s_desc_size != sizeof(struct ext2_group_desc)) {
+    testPrintE("Can't handle ext4 block group descriptor size of %d",
+               sb.s_desc_size);
+    return false;
+  }
+
+  // Read first block group descriptor, decrement free block count, and
+  // write it back out.
+  if (lseek(blk_fd, block_size, SEEK_SET) == -1) {
+    testPrintE("Cannot lseek to ext4 block group descriptor table to read");
+    return false;
+  }
+
+  // Read in block group descriptors till we read one that has at least one free
+  // block.
+  struct ext2_group_desc gd;
+  for (int i = 0; i < num_bgs; i++) {
+    if (read(blk_fd, &gd, sizeof(gd)) != sizeof(gd)) {
+      testPrintE("Cannot read ext4 group descriptor %d", i);
+      return false;
+    }
+    if (gd.bg_free_blocks_count) {
+      break;
+    }
+  }
+
+  gd.bg_free_blocks_count--;
+
+  if (lseek(blk_fd, -sizeof(gd), SEEK_CUR) == -1) {
+    testPrintE("Cannot lseek to ext4 block group descriptor table to write");
+    return false;
+  }
+
+  if (write(blk_fd, &gd, sizeof(gd)) != sizeof(gd)) {
+    testPrintE("Cannot write modified ext4 group descriptor");
+    return false;
+  }
+  return true;
+}
+
+}  // namespace ext4
+
+class FsRecoveryTest : public ::testing::Test {
+ protected:
+  FsRecoveryTest() : fs_type(FS_UNKNOWN), blk_fd_(-1) {}
+
+  bool setCacheInfoFromFstab() {
+    fs_type = FS_UNKNOWN;
+    char propbuf[PROPERTY_VALUE_MAX];
+    property_get("ro.hardware", propbuf, "");
+    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
+
+    struct fstab *fstab = fs_mgr_read_fstab(fstab_filename);
+    if (!fstab) {
+      testPrintE("failed to open %s\n", fstab_filename);
+    } else {
+      // Loop through entries looking for cache.
+      for (int i = 0; i < fstab->num_entries; ++i) {
+        if (!strcmp(fstab->recs[i].mount_point, "/cache")) {
+          strcpy(blk_path_, fstab->recs[i].blk_device);
+          if (!strcmp(fstab->recs[i].fs_type, "ext4")) {
+            fs_type = FS_EXT4;
+            break;
+          } else if (!strcmp(fstab->recs[i].fs_type, "f2fs")) {
+            fs_type = FS_F2FS;
+            break;
+          }
+        }
+      }
+      fs_mgr_free_fstab(fstab);
+    }
+    return fs_type != FS_UNKNOWN;
+  }
+
+  bool unmountCache() {
+    char cache_str[] = "/cache";
+    char *umount_argv[] = {
+      UMOUNT_BIN,
+      cache_str,
+    };
+    int status;
+    return android_fork_execvp_ext(ARRAY_SIZE(umount_argv), umount_argv,
+                                   NULL, true, LOG_KLOG, false, NULL,
+                                   NULL, 0) >= 0;
+  }
+
+  bool mountAll() {
+    char storage_str[] = "storage";
+    char mountall_str[] = "mountall";
+    char *mountall_argv[] = {
+      VDC_BIN,
+      storage_str,
+      mountall_str,
+    };
+    int status;
+    return android_fork_execvp_ext(ARRAY_SIZE(mountall_argv), mountall_argv,
+                                   NULL, true, LOG_KLOG, false, NULL,
+                                   NULL, 0) >= 0;
+  }
+
+  int getCacheBlkFd() {
+    if (blk_fd_ == -1) {
+      blk_fd_ = open(blk_path_, O_RDWR);
+    }
+    return blk_fd_;
+  }
+
+  void closeCacheBlkFd() {
+    if (blk_fd_ > -1) {
+      close(blk_fd_);
+    }
+    blk_fd_ = -1;
+  }
+
+  void assertCacheHealthy() {
+    const char* test_file = "/cache/FsRecoveryTestGarbage.txt";
+    DataFileVerifier file_verify(test_file);
+    file_verify.verify_write();
+    file_verify.verify_read();
+  }
+
+  virtual void SetUp() {
+    assertCacheHealthy();
+    ASSERT_TRUE(setCacheInfoFromFstab());
+  }
+
+  virtual void TearDown() {
+    // Ensure /cache partition is accessible, mounted and healthy for other
+    // tests.
+    closeCacheBlkFd();
+    ASSERT_TRUE(mountAll());
+    assertCacheHealthy();
+  }
+
+  Fs_Type fs_type;
+
+ private:
+  char blk_path_[FILENAME_MAX];
+  int blk_fd_;
+};
+
+TEST_F(FsRecoveryTest, EXT4_CorruptGdt) {
+  if (fs_type != FS_EXT4) {
+    return;
+  }
+  // Setup test file in /cache.
+  const char* test_file = "/cache/CorruptGdtGarbage.txt";
+  DataFileVerifier file_verify(test_file);
+  file_verify.verify_write();
+  // Unmount and corrupt /cache gdt.
+  ASSERT_TRUE(unmountCache());
+  ASSERT_TRUE(ext4::corruptGdtFreeBlock(getCacheBlkFd()));
+  closeCacheBlkFd();
+  ASSERT_TRUE(mountAll());
+
+  // Verify results.
+  file_verify.verify_read();
+}
+
+TEST_F(FsRecoveryTest, EXT4_SetErrorBit) {
+  if (fs_type != FS_EXT4) {
+    return;
+  }
+  // Setup test file in /cache.
+  const char* test_file = "/cache/ErrorBitGarbagetxt";
+  DataFileVerifier file_verify(test_file);
+  file_verify.verify_write();
+
+  // Unmount and set /cache super block error bit.
+  ASSERT_TRUE(unmountCache());
+  ASSERT_TRUE(ext4::setSbErrorBit(getCacheBlkFd()));
+  closeCacheBlkFd();
+  ASSERT_TRUE(mountAll());
+
+  // Verify results.
+  file_verify.verify_read();
+  struct ext4_super_block sb;
+  ASSERT_TRUE(ext4::getSuperBlock(getCacheBlkFd(), &sb));
+  // Verify e2fsck has recovered the error bit of sb.
+  ASSERT_FALSE(sb.s_state & 0x2);
+}
+}  // namespace android
diff --git a/tests/icachetest/Android.mk b/tests/icachetest/Android.mk
new file mode 100644
index 0000000..132efd3
--- /dev/null
+++ b/tests/icachetest/Android.mk
@@ -0,0 +1,15 @@
+# Copyright 2006 The Android Open Source Project
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= icache_main.c icache.S icache2.S
+
+LOCAL_SHARED_LIBRARIES := libc
+
+LOCAL_MODULE:= icache
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_TARGET_ARCH := arm
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/icachetest/icache.S b/tests/icachetest/icache.S
new file mode 100644
index 0000000..fbe8fa7
--- /dev/null
+++ b/tests/icachetest/icache.S
@@ -0,0 +1,181 @@
+/*
+ *  icache.s
+ *  
+ *
+ *  Copyright 2005 The Android Open Source Project
+ *
+ */
+
+	.text
+    .global icache_test
+    .type icache_test, %function
+    .align
+	
+
+#define LOOP                             \
+        subs    r2, r2, #1             ; \
+        mov     r0, r0                 ; \
+        mov     r0, r0                 ; \
+        mov     r0, r0                 ; \
+        mov     r0, r0                 ; \
+        mov     r0, r0                 ; \
+        beq     end_loop               ; \
+        mov     r0, r0                 ; \
+
+
+
+	/*
+	 * r0 = loop_count
+	 * r1 = step
+	 */
+
+    .align  5
+
+icache_test:
+        mov     r0, r0
+        mov     r0, r0
+        mov     r0, r0
+        mov     r0, r0
+        mov     r0, r0
+
+end_loop:
+		subs      r0, r0, r1
+        mov       r2, r1
+		bxmi      lr
+		
+
+		/* here we're aligned on a cache line */
+
+		/* each loop iteration is one cache line 
+		   repeat this block 2048 times... */
+
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+	
+		b		end_loop
diff --git a/tests/icachetest/icache2.S b/tests/icachetest/icache2.S
new file mode 100644
index 0000000..2a204ce
--- /dev/null
+++ b/tests/icachetest/icache2.S
@@ -0,0 +1,171 @@
+/*
+ *  icache.s
+ *  
+ *
+ *  Copyright 2005 The Android Open Source Project
+ *
+ */
+
+    .text
+    .align
+    
+    .global icache_test2
+    .type icache_test2, %function
+
+#define LOOP                             \
+        mov     r0, r0                 ; \
+        mov     r0, r0                 ; \
+        mov     r0, r0                 ; \
+        mov     r0, r0                 ; \
+        mov     r0, r0                 ; \
+        mov     r0, r0                 ; \
+        mov     r0, r0                 ; \
+        mov     r0, r0                 ;
+
+
+    /*
+     * r0 = loop_count
+     * r1 = step
+     * r2 = mask
+     */
+
+icache_test2:
+end_loop:
+        
+        /* each loop iteration is one cache line 
+           repeat this block 2048 times... */
+
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+        LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP 
+    
+        subs    r0, r0, #1
+        bgt     end_loop
+        bx      lr
+
+        
diff --git a/tests/icachetest/icache_main.c b/tests/icachetest/icache_main.c
new file mode 100644
index 0000000..93f36d4
--- /dev/null
+++ b/tests/icachetest/icache_main.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <sys/time.h>
+
+extern void icache_test(long count, long step);
+extern void icache_test2(long count);
+
+int main() 
+{
+    printf("[bytes]\t[us]\n");
+
+    struct timeval now, tm;
+    long long t;
+    long MBs;
+    long i;
+    long step = 32;
+    for (i=0 ; step<=2048 ; i++, step+=32) 
+    {
+        long value;
+        gettimeofday(&now, 0);
+        icache_test(0x800000L, step);
+        gettimeofday(&tm, 0);
+        t = (tm.tv_sec*1000000LL+tm.tv_usec) - (now.tv_sec*1000000LL+now.tv_usec);
+        printf("%6ld\t%lld\n", step*32, t);
+    }
+
+    gettimeofday(&now, 0);
+    icache_test2(0x800000L / 2048);
+    gettimeofday(&tm, 0);
+    t = (tm.tv_sec*1000000LL+tm.tv_usec) - (now.tv_sec*1000000LL+now.tv_usec);
+    MBs = (8388608LL*32*1000000) / (t * (1024*1024));
+    printf("\n%6lld us\t%ld MB/s\n", t, MBs);
+    
+    return 0;
+}
diff --git a/tests/include/testUtil.h b/tests/include/testUtil.h
new file mode 100644
index 0000000..3b75914
--- /dev/null
+++ b/tests/include/testUtil.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 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 _TESTUTIL_H_
+#define _TESTUTIL_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+// Time Utilities
+struct timespec double2ts(double amt);
+struct timeval  double2tv(double amt);
+double ts2double(const struct timespec *val);
+double tv2double(const struct timeval  *val);
+struct timespec tsDelta(const struct timespec *first,
+    const struct timespec *second);
+struct timeval tvDelta(const struct timeval *first,
+    const struct timeval *second);
+
+void testDelay(float amt);
+void testDelaySpin(float amt);
+
+// Pseudo Random Utilities
+int testRandBool(void);
+uint32_t testRand(void);
+uint32_t testRandMod(uint32_t mod);
+double testRandFract(void);
+
+// Testcase Output
+void testSetLogCatTag(const char *tag);
+const char *testGetLogCatTag(void);
+void testPrint(FILE *stream, const char *fmt, ...);
+#define testPrintI(...) do { \
+        testPrint(stdout, __VA_ARGS__); \
+    } while (0)
+#define testPrintE(...) do { \
+        testPrint(stderr, __VA_ARGS__); \
+    } while (0)
+
+// Hex Dump
+void testXDump(const void *buf, size_t size);
+void testXDumpSetIndent(uint8_t indent);
+uint8_t testXDumpGetIndent(void);
+void testXDumpSetOffset(uint64_t offset);
+uint64_t testXDumpGetOffset(void);
+
+// Command Execution
+void testExecCmd(const char *cmd);
+
+__END_DECLS
+
+#endif
diff --git a/tests/iptables/Android.mk b/tests/iptables/Android.mk
new file mode 100644
index 0000000..56a3fa8
--- /dev/null
+++ b/tests/iptables/Android.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2011 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.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/tests/iptables/qtaguid/Android.mk b/tests/iptables/qtaguid/Android.mk
new file mode 100644
index 0000000..b92b662
--- /dev/null
+++ b/tests/iptables/qtaguid/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2011 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := socketTag
+LOCAL_SRC_FILES := socketTag.cpp
+LOCAL_SHARED_LIBRARIES += libcutils libutils liblog
+LOCAL_STATIC_LIBRARIES += libtestUtil
+LOCAL_C_INCLUDES += system/extras/tests/include
+LOCAL_CFLAGS += -fno-strict-aliasing
+
+include $(BUILD_NATIVE_TEST)
diff --git a/tests/iptables/qtaguid/socketTag.cpp b/tests/iptables/qtaguid/socketTag.cpp
new file mode 100644
index 0000000..24a87e0
--- /dev/null
+++ b/tests/iptables/qtaguid/socketTag.cpp
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2011 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 requied 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.
+ *
+ */
+
+/*
+ * This socket tagging test is to ensure that the
+ * netfilter/xt_qtaguid kernel module somewhat behaves as expected
+ * with respect to tagging sockets.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <gtest/gtest.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <string>
+
+#define LOG_TAG "socketTagTest"
+#include <utils/Log.h>
+#include <testUtil.h>
+
+namespace android {
+
+class SockInfo {
+public:
+    SockInfo() : fd(-1), addr(NULL) {};
+    int setup(uint64_t tag);
+    bool checkTag(uint64_t tag, uid_t uid);
+    int fd;
+    void *addr;
+};
+
+
+int openCtrl() {
+    int ctrl;
+    ctrl = open("/proc/net/xt_qtaguid/ctrl", O_RDWR);
+    if (!ctrl) {
+       testPrintE("qtaguid ctrl open failed: %s", strerror(errno));
+    }
+    return ctrl;
+}
+
+int doCtrlCommand(const char *fmt, ...)
+    __attribute__((__format__(__printf__, 1, 2)));
+
+int doCtrlCommand(const char *fmt, ...) {
+    char *buff;
+    int ctrl;
+    int res;
+    va_list argp;
+
+    va_start(argp, fmt);
+    ctrl = openCtrl();
+    vasprintf(&buff, fmt, argp);
+    errno = 0;
+    res = write(ctrl, buff, strlen(buff));
+    testPrintI("cmd: '%s' res=%d %d/%s", buff, res, errno, strerror(errno));
+    close(ctrl);
+    free(buff);
+    va_end(argp);
+    return res;
+}
+
+
+int writeModuleParam(const char *param, const char *data) {
+    int param_fd;
+    int res;
+    std::string filename("/sys/module/xt_qtaguid/parameters/");
+
+    filename += param;
+    param_fd = open(filename.c_str(), O_WRONLY);
+    if (param_fd < 0) {
+        testPrintE("qtaguid param open failed: %s", strerror(errno));
+        return -1;
+    }
+    res = write(param_fd, data, strlen(data));
+    if (res < 0) {
+        testPrintE("qtaguid param write failed: %s", strerror(errno));
+    }
+    close(param_fd);
+    return res;
+}
+
+/*----------------------------------------------------------------*/
+int SockInfo::setup(uint64_t tag) {
+    fd = socket(AF_INET, SOCK_STREAM, 0);
+    if (fd < 0) {
+        testPrintE("socket creation failed: %s", strerror(errno));
+        return -1;
+    }
+    if (doCtrlCommand("t %d %" PRIu64, fd, tag) < 0) {
+        testPrintE("socket setup: failed to tag");
+        close(fd);
+        return -1;
+    }
+    if (!checkTag(tag, getuid())) {
+        testPrintE("socket setup: Unexpected results: tag not found");
+        close(fd);
+        return -1;
+    }
+    if (doCtrlCommand("u %d", fd) < 0) {
+        testPrintE("socket setup: Unexpected results");
+        close(fd);
+        return -1;
+    }
+    return 0;
+}
+
+/* checkTag() also tries to lookup the socket address in the kernel and
+ * return it when *addr  == NULL.
+ * This allows for better look ups when another process is also setting the same
+ * tag + uid. But it is not fool proof.
+ * Without the kernel reporting more info on who setup the socket tag, it is
+ * not easily verifiable from user-space.
+ * Returns: true if tag found.
+ */
+bool SockInfo::checkTag(uint64_t acct_tag, uid_t uid) {
+    int ctrl_fd;
+    ctrl_fd = openCtrl();
+    char ctrl_data[1024];
+    ssize_t read_size;
+    char *buff;
+    char *pos;
+    int res;
+    char *match_template;
+    uint64_t k_tag;
+    uint32_t k_uid;
+    uint64_t full_tag;
+    long dummy_count;
+    pid_t dummy_pid;
+
+    read_size = read(ctrl_fd, ctrl_data, sizeof(ctrl_data));
+    if (read_size < 0) {
+       testPrintE("Unable to read active tags from ctrl %d/%s",
+                  errno, strerror(errno));
+    }
+    ctrl_data[read_size] = '\0';
+    testPrintI("<ctrl_raw_data>\n%s</ctrl_raw_data>", ctrl_data);
+
+    if (addr) {
+        assert(sizeof(void*) == sizeof(long int));  // Why does %p use 0x? grrr. %lx.
+        asprintf(&match_template, "sock=%" PRIxPTR " %s", (uintptr_t)addr, "tag=0x%" PRIx64" (uid=%u)");
+    }
+    else {
+        /* Allocate for symmetry */
+        asprintf(&match_template, "%s", " tag=0x%" PRIx64 " (uid=%u)");
+    }
+
+    full_tag = acct_tag | uid;
+
+    asprintf(&buff, match_template, full_tag | uid, uid);
+    testPrintI("looking for '%s'", buff);
+    pos = strstr(ctrl_data, buff);
+
+    if (pos && !addr) {
+        assert(sizeof(void*) == sizeof(long int));  // Why does %p use 0x? grrr. %lx.
+        res = sscanf(pos - strlen("sock=1234abcd"),
+                     "sock=%" SCNxPTR " tag=0x%" SCNx64 " (uid=%" SCNu32 ") pid=%u f_count=%lu",
+                     (uintptr_t *)&addr, &k_tag, &k_uid, &dummy_pid, &dummy_count );
+        if (!(res == 5 && k_tag == full_tag && k_uid == uid)) {
+            testPrintE("Unable to read sock addr res=%d", res);
+           addr = 0;
+        }
+        else {
+            testPrintI("Got sock_addr %lx", addr);
+        }
+    }
+    free(buff);
+    free(match_template);
+    close(ctrl_fd);
+    return pos != NULL;
+}
+
+
+class SocketTaggingTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        ctrl_fd = -1;
+        dev_fd = -1;
+        my_uid = getuid();
+        my_pid = getpid();
+        srand48(my_pid * my_uid);
+        // Adjust fake UIDs and tags so that multiple instances can run in parallel.
+        fake_uid = testRand();
+        fake_uid2 = testRand();
+        valid_tag1 = ((uint64_t)my_pid << 48) | ((uint64_t)testRand() << 32);
+        valid_tag2 = ((uint64_t)my_pid << 48) | ((uint64_t)testRand() << 32);
+        valid_tag2 &= 0xffffff00ffffffffllu;  // Leave some room to make counts visible.
+        testPrintI("* start: pid=%lu uid=%lu uid1=0x%lx/%lu uid2=0x%lx/%lu"
+                   " tag1=0x%" PRIx64 "/%" PRIu64 " tag2=0x%" PRIx64 "/% " PRIu64,
+                   (unsigned long)my_pid, (unsigned long)my_uid,
+                   (unsigned long)fake_uid, (unsigned long)fake_uid,
+                   (unsigned long)fake_uid2, (unsigned long)fake_uid2,
+                   valid_tag1, valid_tag1, valid_tag2, valid_tag2);
+        max_uint_tag = 0xffffffff00000000llu;
+        max_uint_tag = 1llu << 63 | (((uint64_t)my_pid << 48) ^ max_uint_tag);
+
+        testPrintI("kernel has qtaguid");
+        ctrl_fd = openCtrl();
+        ASSERT_GE(ctrl_fd, 0) << "qtaguid ctrl open failed";
+        close(ctrl_fd);
+        dev_fd = open("/dev/xt_qtaguid", O_RDONLY);
+        EXPECT_GE(dev_fd, 0) << "qtaguid dev open failed";
+
+        // We want to clean up any previous faulty test runs.
+        testPrintI("delete command does not fail");
+        EXPECT_GE(doCtrlCommand("d 0 %u", fake_uid), 0) << "Failed to delete fake_uid";
+        EXPECT_GE(doCtrlCommand("d 0 %u", fake_uid2), 0) << "Failed to delete fake_uid2";
+        EXPECT_GE(doCtrlCommand("d 0 %u", my_uid), 0) << "Failed to delete my_uid";
+
+        testPrintI("setup sock0 and addr via tag");
+        ASSERT_FALSE(sock0.setup(valid_tag1))  << "socket0 setup failed";
+        testPrintI("setup sock1 and addr via tag");
+        ASSERT_FALSE(sock1.setup(valid_tag1))  << "socket1 setup failed";
+    }
+
+   virtual void TearDown() {
+       if (dev_fd >= 0) {
+           close(dev_fd);
+       }
+       if (ctrl_fd >= 0) {
+           close(ctrl_fd);
+       }
+   }
+
+   SockInfo sock0;
+   SockInfo sock1;
+   int ctrl_fd;
+   int dev_fd;
+   uid_t fake_uid;
+   uid_t fake_uid2;
+   uid_t my_uid;
+   pid_t my_pid;
+   uint64_t valid_tag1;
+   uint64_t valid_tag2;
+   uint64_t max_uint_tag;
+   static const uint64_t invalid_tag1 = 0x0000000100000001llu;
+   static const int max_tags = 5;
+};
+
+TEST_F(SocketTaggingTest, TagData) {
+    max_uint_tag = 0xffffffff00000000llu;
+    char *max_tags_str;
+
+    testPrintI("setup tag limit");
+    asprintf(&max_tags_str, "%d", max_tags);
+    ASSERT_GE(writeModuleParam("max_sock_tags", max_tags_str), 0) << "Failed to setup tag limit";
+
+    testPrintI("tag quota reach limit");
+    for (int cnt = 0; cnt < max_tags; cnt++ ) {
+        uint64_t tag = valid_tag2 + ((uint64_t)cnt << 32);
+        EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, tag , fake_uid2), 0)
+            << "Tagging within limit failed";
+        EXPECT_TRUE(sock0.checkTag(tag, fake_uid2))<<  "Unexpected results: tag not found";
+    }
+
+    testPrintI("tag quota go over limit");
+    uint64_t new_tag = valid_tag2 + ((uint64_t)max_tags << 32);
+    EXPECT_LT(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, new_tag, fake_uid2), 0);
+    EXPECT_TRUE(sock0.checkTag(valid_tag2 + (((uint64_t)max_tags - 1) << 32),
+                               fake_uid2)) << "Unexpected results: tag not found";
+
+    testPrintI("valid untag");
+    EXPECT_GE(doCtrlCommand("u %d", sock0.fd), 0);
+    EXPECT_FALSE(sock0.checkTag(valid_tag2 + (((uint64_t)max_tags - 1) << 32), fake_uid2))
+        << "Untagged tag should not be there";
+
+    testPrintI("tag after untag should not free up max tags");
+    uint64_t new_tag2 = valid_tag2 + ((uint64_t)max_tags << 32);
+    EXPECT_LT(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, new_tag2 , fake_uid2), 0);
+    EXPECT_FALSE(sock0.checkTag(valid_tag2 + ((uint64_t)max_tags << 32), fake_uid2))
+        << "Tag should not be there";
+
+    testPrintI("delete one tag");
+    uint64_t new_tag3 = valid_tag2 + (((uint64_t)max_tags / 2) << 32);
+    EXPECT_GE(doCtrlCommand("d %" PRIu64 " %u", new_tag3, fake_uid2), 0);
+
+    testPrintI("2 tags after 1 delete pass/fail");
+    uint64_t new_tag4;
+    new_tag4 = valid_tag2 + (((uint64_t)max_tags + 1 ) << 32);
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, new_tag4 , fake_uid2), 0);
+    EXPECT_TRUE(sock0.checkTag(valid_tag2 + (((uint64_t)max_tags + 1) << 32), fake_uid2))
+        << "Tag not found";
+    new_tag4 = valid_tag2 + (((uint64_t)max_tags + 2 ) << 32);
+    EXPECT_LT(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, new_tag4 , fake_uid2), 0);
+    EXPECT_FALSE(sock0.checkTag(valid_tag2 + (((uint64_t)max_tags + 2) << 32), fake_uid2))
+        << "Tag should not be there";
+
+    /* TODO(jpa): test tagging two different sockets with same tags and
+     * check refcounts  the tag_node should be +2
+     */
+}
+
+TEST_F(SocketTaggingTest, InsufficientArgsFails) {
+    // Insufficient args. Expected failure
+    EXPECT_LE(doCtrlCommand("t"), 0) << "Insufficient args, should fail.";
+}
+
+TEST_F(SocketTaggingTest, BadCommandFails) {
+    // Bad command. Expected failure";
+    EXPECT_LE(doCtrlCommand("?"), 0) << "Bad command, should fail";
+}
+
+TEST_F(SocketTaggingTest, NoTagNoUid) {
+    // no tag, no uid
+    EXPECT_GE(doCtrlCommand("t %d", sock0.fd), 0);
+    ASSERT_TRUE(sock0.checkTag(0, my_uid))  << "Tag not found";
+}
+
+TEST_F(SocketTaggingTest, InvalidTagFail) {
+    // Invalid tag. Expected failure
+    EXPECT_LE(doCtrlCommand("t %d %" PRIu64, sock0.fd, invalid_tag1), 0);
+    ASSERT_FALSE(sock0.checkTag(invalid_tag1, my_uid)) << "Tag should not be there";
+}
+
+TEST_F(SocketTaggingTest, ValidTagWithNoUid) {
+    // Valid tag with no uid
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64, sock0.fd, valid_tag1), 0);
+    EXPECT_TRUE(sock0.checkTag(valid_tag1, my_uid)) << "Tag not found";
+}
+
+TEST_F(SocketTaggingTest, ValidUntag) {
+    // Valid untag
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64, sock0.fd, valid_tag1), 0);
+    EXPECT_TRUE(sock0.checkTag(valid_tag1, my_uid)) << "Tag not found";
+    EXPECT_GE(doCtrlCommand("u %d", sock0.fd), 0);
+    EXPECT_FALSE(sock0.checkTag(valid_tag1, my_uid)) << "Tag should be removed";
+}
+
+TEST_F(SocketTaggingTest, ValidFirsttag) {
+    // Valid 1st tag
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag2, fake_uid), 0);
+    EXPECT_TRUE(sock0.checkTag(valid_tag2, fake_uid)) << "Tag not found.";
+}
+
+TEST_F(SocketTaggingTest, ValidReTag) {
+    // Valid re-tag
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag2, fake_uid), 0);
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag2, fake_uid), 0);
+    EXPECT_TRUE(sock0.checkTag(valid_tag2, fake_uid)) << "Tag not found.";
+}
+
+TEST_F(SocketTaggingTest, ValidReTagWithAcctTagChange) {
+    // Valid re-tag with acct_tag change
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag2, fake_uid), 0);
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag1, fake_uid), 0);
+    EXPECT_TRUE(sock0.checkTag(valid_tag1, fake_uid)) << "Tag not found.";
+}
+
+TEST_F(SocketTaggingTest, ReTagWithUidChange) {
+    // Re-tag with uid change
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag1, fake_uid), 0);
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag2, fake_uid2), 0);
+}
+
+TEST_F(SocketTaggingTest, Valid64BitAcctTag) {
+    // Valid 64bit acct tag
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64, sock0.fd, max_uint_tag), 0);
+    EXPECT_TRUE(sock0.checkTag(max_uint_tag, my_uid)) << "Tag not found.";
+}
+
+TEST_F(SocketTaggingTest, TagAnotherSocket) {
+    testPrintI("Tag two sockets");
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64, sock0.fd, max_uint_tag), 0);
+    EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock1.fd, valid_tag1, fake_uid2), 0);
+    EXPECT_TRUE(sock1.checkTag(valid_tag1, fake_uid2)) << "Tag not found.";
+    testPrintI("Untag socket0 of them only.");
+    EXPECT_GE(doCtrlCommand("u %d", sock0.fd), 0);
+    EXPECT_FALSE(sock0.checkTag(max_uint_tag, fake_uid)) << "Tag should not be there";
+    EXPECT_TRUE(sock1.checkTag(valid_tag1, fake_uid2)) << "Tag not found";
+    testPrintI("Now untag socket1 as well.");
+    EXPECT_GE(doCtrlCommand("u %d", sock1.fd), 0);
+    EXPECT_FALSE(sock1.checkTag(valid_tag1, fake_uid2)) << "Tag should not be there";
+}
+
+TEST_F(SocketTaggingTest, TagInvalidSocketFail) {
+    // Invalid tag. Expected failure
+    close(sock0.fd);
+    EXPECT_LE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag1, my_uid), 0);
+    EXPECT_FALSE(sock0.checkTag(valid_tag1, my_uid)) << "Tag should not be there";
+}
+
+TEST_F(SocketTaggingTest, UntagInvalidSocketFail) {
+    // Invalid untag. Expected failure";
+    close(sock1.fd);
+    EXPECT_LE(doCtrlCommand("u %d", sock1.fd), 0);
+}
+
+}  // namespace android
diff --git a/tests/kernel.config/Android.mk b/tests/kernel.config/Android.mk
new file mode 100644
index 0000000..c05fcc8
--- /dev/null
+++ b/tests/kernel.config/Android.mk
@@ -0,0 +1,79 @@
+# Copyright 2016 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
+
+test_c_flags := \
+    -fstack-protector-all \
+    -g \
+    -Wall -Wextra \
+    -Werror \
+    -fno-builtin \
+    -std=gnu++11
+
+# Required Tests
+cts_src_files := \
+    aslr_test.cpp \
+    multicast_test.cpp \
+    pstore_test.cpp \
+    sysvipc_test.cpp \
+    logger_test.cpp
+
+# Required plus Recommended Tests
+test_src_files := \
+    $(cts_src_files) \
+    aslr_rec_test.cpp \
+    mmc_max_speed_test.cpp \
+
+cts_executable := CtsKernelConfigTestCases
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := kernel-config-unit-tests
+LOCAL_MODULE_TAGS := tests
+LOCAL_CFLAGS := $(test_c_flags)
+LOCAL_CFLAGS := -DHAS_KCMP
+LOCAL_SRC_FILES := $(test_src_files)
+include $(BUILD_NATIVE_TEST)
+
+ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(cts_executable)_list
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(test_c_flags)
+LOCAL_SRC_FILES := $(cts_src_files)
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_CXX_STL := libc++
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_HOST_NATIVE_TEST)
+
+endif  # ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(cts_executable)
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(test_c_flags)
+LOCAL_CFLAGS := -DHAS_KCMP
+LOCAL_SRC_FILES := $(cts_src_files)
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_STATIC_LIBRARIES := libgtest libgtest_main
+
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+LOCAL_CTS_TEST_PACKAGE := android.kernel.config
+LOCAL_CTS_GTEST_LIST_EXECUTABLE := $(ALL_MODULES.$(cts_executable)_list$(HOST_2ND_ARCH_MODULE_SUFFIX).INSTALLED)
+include $(BUILD_CTS_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+    scrape_mmap_addr.cpp
+
+LOCAL_MODULE := scrape_mmap_addr
+include $(BUILD_NATIVE_TEST)
diff --git a/tests/kernel.config/AndroidTest.xml b/tests/kernel.config/AndroidTest.xml
new file mode 100644
index 0000000..4fe3192
--- /dev/null
+++ b/tests/kernel.config/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<configuration description="Config for CTS Kernel Config test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="CtsKernelConfigTestCases->/data/local/tmp/CtsKernelConfigTestCases" />
+        <option name="append-bitness" value="true" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="CtsKernelConfigTestCases" />
+    </test>
+</configuration>
diff --git a/tests/kernel.config/aslr_rec_test.cpp b/tests/kernel.config/aslr_rec_test.cpp
new file mode 100644
index 0000000..e154424
--- /dev/null
+++ b/tests/kernel.config/aslr_rec_test.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "aslr_test.h"
+
+/* run tests if on supported arch */
+#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__arm__)
+
+/* make sure the default entropy values matches what we expect */
+TEST_F(AslrMmapTest, match_default) {
+    if (user32) {
+        // running 32-bit userspace on 64-bit kernel, only compat used.
+        return;
+    } else {
+        EXPECT_EQ(def, get_mmap_rnd_bits(false));
+    }
+}
+
+/* make sure the default compat entropy values matches what we expect */
+TEST_F(AslrMmapTest, match_compat_default) {
+    if (compat || user32)
+        EXPECT_EQ(def_cmpt, get_mmap_rnd_bits(true));
+}
+
+/* make sure we can't set entropy below a minimum threshold */
+TEST_F(AslrMmapTest, match_min) {
+    if (user32) {
+        // running 32-bit userspace on 64-bit kernel, only compat used.
+        return;
+    } else {
+        EXPECT_FALSE(set_mmap_rnd_bits(min - 1, false));
+        EXPECT_TRUE(set_mmap_rnd_bits(min, false));
+        EXPECT_EQ(min, get_mmap_rnd_bits(false));
+    }
+}
+
+/* make sure we can't set compat entropy below a minimum threshold */
+TEST_F(AslrMmapTest, match_compat_min) {
+    if (compat || user32) {
+        EXPECT_FALSE(set_mmap_rnd_bits(min_cmpt - 1, true));
+        EXPECT_TRUE(set_mmap_rnd_bits(min_cmpt, true));
+        EXPECT_EQ(min_cmpt, get_mmap_rnd_bits(true));
+    }
+}
+
+/* make sure we can't set entropy above a maximum threshold */
+TEST_F(AslrMmapTest, match_max) {
+    if (user32) {
+        // running 32-bit userspace on 64-bit kernel, only compat used.
+        return;
+    } else {
+        EXPECT_FALSE(set_mmap_rnd_bits(max + 1, false));
+        EXPECT_TRUE(set_mmap_rnd_bits(max, false));
+        EXPECT_EQ(max, get_mmap_rnd_bits(false));
+    }
+}
+
+/* make sure we can't set compat entropy above a maximum threshold */
+TEST_F(AslrMmapTest, match_compat_max) {
+    if (compat || user32) {
+        EXPECT_FALSE(set_mmap_rnd_bits(max_cmpt + 1, true));
+        EXPECT_TRUE(set_mmap_rnd_bits(max_cmpt, true));
+        EXPECT_EQ(max_cmpt, get_mmap_rnd_bits(true));
+    }
+}
+
+/* make sure observed entropy is what we expect when we set min value */
+TEST_F(AslrMmapTest, entropy_min) {
+    if (user32) {
+        // running 32-bit userspace on 64-bit kernel, only compat used.
+        return;
+    } else {
+        EXPECT_TRUE(set_mmap_rnd_bits(min, false));
+        EXPECT_EQ(min, calc_mmap_entropy(path, lib, 16));
+    }
+}
+
+/* make sure observed compat entropy is what we expect when we set min value */
+TEST_F(AslrMmapTest, entropy_cmpt_min) {
+    if (compat || user32) {
+        EXPECT_TRUE(set_mmap_rnd_bits(min_cmpt, true));
+        EXPECT_EQ(min_cmpt, calc_mmap_entropy(SCRAPE_PATH_32, SCRAPE_LIB_32, 16));
+    }
+}
+
+/* make sure observed entropy is what we expect when we set max value */
+TEST_F(AslrMmapTest, entropy_max) {
+    if (user32) {
+        // running 32-bit userspace on 64-bit kernel, only compat used.
+        return;
+    } else {
+        EXPECT_TRUE(set_mmap_rnd_bits(max, false));
+        EXPECT_EQ(max, calc_mmap_entropy(path, lib, 16));
+    }
+}
+
+/* make sure observed compat entropy is what we expect when we set max value */
+TEST_F(AslrMmapTest, entropy_cmpt_max) {
+    if (compat || user32) {
+        EXPECT_TRUE(set_mmap_rnd_bits(max_cmpt, true));
+        EXPECT_EQ(max_cmpt, calc_mmap_entropy(SCRAPE_PATH_32, SCRAPE_LIB_32, 16));
+    }
+}
+
+/* make sure observed entropy is what we expect for default value */
+TEST_F(AslrMmapTest, entropy_def) {
+    if (user32) {
+        // running 32-bit userspace on 64-bit kernel, only compat used.
+        return;
+    } else {
+        EXPECT_EQ(def, calc_mmap_entropy(path, lib, 16));
+    }
+}
+
+/* make sure observed entropy is what we expect for default compat value */
+TEST_F(AslrMmapTest, entropy_cmpt_def) {
+    if (compat || user32) {
+        EXPECT_EQ(def_cmpt, calc_mmap_entropy(SCRAPE_PATH_32, SCRAPE_LIB_32, 16));
+    }
+}
+
+#endif /* supported arch */
diff --git a/tests/kernel.config/aslr_test.cpp b/tests/kernel.config/aslr_test.cpp
new file mode 100644
index 0000000..ef47f4f
--- /dev/null
+++ b/tests/kernel.config/aslr_test.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "aslr_test.h"
+
+unsigned int get_mmap_rnd_bits(bool compat) {
+    std::string path;
+
+    if (compat)
+        path = PROCFS_COMPAT_PATH;
+    else
+        path = PROCFS_PATH;
+
+    std::ifstream bi_file(path);
+    if (!bi_file)
+        return false;
+    std::string str_rec;
+    bi_file >> str_rec;
+
+    return stoi(str_rec);
+}
+
+bool set_mmap_rnd_bits(unsigned int new_val, bool compat) {
+    std::string path;
+
+    if (compat)
+        path = "/proc/sys/vm/mmap_rnd_compat_bits";
+    else
+        path = "/proc/sys/vm/mmap_rnd_bits";
+
+    std::ofstream bo_file(path, std::ios::out);
+    if (!bo_file)
+        return false;
+
+    std::string str_val = std::to_string(new_val);
+    bo_file << str_val << std::flush;
+    bo_file.close();
+
+    // check to make sure it was recorded
+    std::ifstream bi_file(path);
+    if (!bi_file)
+        return false;
+    std::string str_rec;
+    bi_file >> str_rec;
+    bi_file.close();
+    if (str_val.compare(str_rec) != 0)
+        return false;
+    return true;
+}
+
+std::string scrape_addr(const char *exec_name, const char *lib_match) {
+    pid_t pid;
+    int fd[2];
+    char buff[MAX_ADDR_LEN];
+    int len, status;
+    if(pipe(fd)) {
+        std::cerr << "Error creating pipe:" << strerror(errno) << "\n";
+        return std::string();
+    }
+
+    if ((pid = fork()) < 0) {
+        std::cerr << "Error creating new process: " << strerror(errno) << "\n";
+        close(fd[0]);
+        close(fd[1]);
+        return std::string();
+    } else if (pid > 0) {
+        // parent
+        close(fd[1]);
+        wait(&status);
+        if (status == -1) {
+            std::cerr << "Unable to find starting address of mmapp'd libc. Aborting.\n";
+            close(fd[0]);
+            return std::string();
+        }
+        len = read(fd[0], buff, MAX_ADDR_LEN - 1);
+        if (len < 0) {
+            std::cerr << "Error reading pipe from child: " << strerror(errno) << "\n";
+            close(fd[0]);
+            return std::string();
+        }
+        buff[len] = '\0';
+        close(fd[0]);
+    } else {
+        // child, dup 'n' exec
+        close(fd[0]);
+        if(dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
+            std::cerr << "Error dup'n pipe to STDOUT of child: " << strerror(errno) << "\n";
+            close(fd[1]);
+            return std::string();
+        }
+        if(execlp(exec_name, exec_name, lib_match, (char *) NULL)) {
+            std::cerr << "Error exec'ing mmap_scraper: " << strerror(errno) << "\n";
+            close(fd[1]);
+            return std::string();
+        }
+    }
+    return std::string(buff, strlen(buff));
+}
+
+unsigned int calc_mmap_entropy(const char *exec_name, const char *lib_match, size_t samp_sz) {
+    uint64_t min_addr = 0, max_addr = 0;
+
+    std::unordered_set<uint64_t> addrs = { };
+
+    // get our first value
+    uint64_t addr = min_addr = max_addr = std::stoll(scrape_addr(exec_name, lib_match), 0, 16);
+    addrs.insert(addr);
+    for (unsigned int i = 0; i < samp_sz - 1; ++i) {
+        std::string addr_str = scrape_addr(exec_name, lib_match);
+        if (addr_str.empty())
+            return 0;
+        addr = std::stoll(addr_str, 0, 16);
+        if (addr < min_addr)
+            min_addr = addr;
+        if (addr >= max_addr)
+            max_addr = addr;
+        addrs.insert(addr);
+    }
+    if (addrs.size() < (samp_sz >> 1)) {
+        std::cerr << "> 50% collisions in mmap addresses, entropy appears to be rigged!";
+        return 0;
+    }
+    unsigned int e_bits = (int) (std::ceil(std::log2(max_addr - min_addr)) - std::log2(getpagesize()));
+    return e_bits;
+}
+
+const char *AslrMmapTest::path;
+const char *AslrMmapTest::lib;
+unsigned int AslrMmapTest::def, AslrMmapTest::min, AslrMmapTest::max;
+bool AslrMmapTest::compat = false, AslrMmapTest::user32 = false;
+unsigned int AslrMmapTest::def_cmpt, AslrMmapTest::min_cmpt, AslrMmapTest::max_cmpt;
+
+void AslrMmapTest::SetUpTestCase() {
+    /* set up per-arch values */
+#if defined(__x86_64__)
+    def = 32;
+    min = 28;
+    max = 32;
+    path = SCRAPE_PATH_64;
+    lib = SCRAPE_LIB_64;
+
+    compat = true;
+    def_cmpt = 16;
+    min_cmpt = 8;
+    max_cmpt = 16;
+
+#elif defined(__i386__)
+    def = 16;
+    min = 8;
+    max = 16;
+    path = SCRAPE_PATH_32;
+    lib = SCRAPE_LIB_32;
+
+    if (!access(PROCFS_COMPAT_PATH, F_OK)) {
+        // running 32 bit userspace over 64-bit kernel
+        user32 = true;
+        def_cmpt = 16;
+        min_cmpt = 8;
+        max_cmpt = 16;
+    }
+
+#elif defined(__aarch64__)
+    unsigned int pgbits = std::log2(getpagesize());
+    def = 24;
+    min = 18 - (pgbits - 12);
+    max = 24;
+    path = SCRAPE_PATH_64;
+    lib = SCRAPE_LIB_64;
+
+    compat = true;
+    def_cmpt = 16;
+    min_cmpt = 11 - (pgbits - 12);
+    max_cmpt = 16;
+
+#elif defined(__arm__)
+    unsigned int pgbits = std::log2(getpagesize());
+    def = 16;
+    min = 8;
+    max = 16;
+    path = SCRAPE_PATH_32;
+    lib = SCRAPE_LIB_32;
+
+    if (!access(PROCFS_COMPAT_PATH, F_OK)) {
+        // running 32 bit userspace over 64-bit kernel
+        user32 = true;
+        def_cmpt = 16;
+        min_cmpt = 11 - (pgbits - 12);;
+        max_cmpt = 16;
+    }
+#endif
+}
+
+void AslrMmapTest::TearDown() {
+    if (!user32)
+        set_mmap_rnd_bits(def, false);
+    if (user32 || compat)
+        set_mmap_rnd_bits(def_cmpt, true);
+}
+
+/* run tests only if on supported arch */
+#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__arm__)
+
+TEST_F(AslrMmapTest, entropy_min_def) {
+    if (user32) {
+        // running 32-bit userspace on 64-bit kernel, only compat used.
+        return;
+    } else {
+        EXPECT_GE(def, calc_mmap_entropy(path, lib, 16));
+    }
+}
+
+TEST_F(AslrMmapTest, entropy_min_cmpt_def) {
+    if (compat || user32) {
+        EXPECT_GE(def_cmpt, calc_mmap_entropy(SCRAPE_PATH_32, SCRAPE_LIB_32, 16));
+    }
+}
+
+#endif /* supported arch */
diff --git a/tests/kernel.config/aslr_test.h b/tests/kernel.config/aslr_test.h
new file mode 100644
index 0000000..355a62a
--- /dev/null
+++ b/tests/kernel.config/aslr_test.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 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 ASLR_TEST_H
+#define ASLR_TEST_H
+
+#include <cmath>
+#include <errno.h>
+#include <fstream>
+#include <iostream>
+#include <stdint.h>
+#include <string>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <unordered_set>
+
+#include <gtest/gtest.h>
+
+#define MAX_ADDR_LEN 256
+
+#define PROCFS_PATH "/proc/sys/vm/mmap_rnd_bits"
+#define PROCFS_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
+
+#define SCRAPE_PATH_64 "/data/nativetest64/scrape_mmap_addr/scrape_mmap_addr"
+#define SCRAPE_PATH_32 "/data/nativetest/scrape_mmap_addr/scrape_mmap_addr"
+#define SCRAPE_LIB_64 "/system/bin/linker64"
+#define SCRAPE_LIB_32 "/system/bin/linker"
+
+class AslrMmapTest : public ::testing::Test {
+  protected:
+    static void SetUpTestCase();
+    static const char *path;
+    static const char *lib;
+    static unsigned int def, min, max;
+    static bool compat, user32;
+    static unsigned int def_cmpt, min_cmpt, max_cmpt;
+
+    void TearDown();
+};
+
+/*
+ * gets the current mmap_rnd_bits value. requires root.
+ */
+unsigned int get_mmap_rnd_bits(bool compat);
+
+/*
+ * sets the corresponding mmap_rnd_bits variable, returns false if couldn't
+ * change. requires root.
+ */
+bool set_mmap_rnd_bits(unsigned int new_val, bool compat);
+
+/*
+ * scrape_addr - get the raw starting address from /proc/child_pid/mmaps
+ */
+std::string scrape_addr(const char *exec_name, const char *lib_match);
+
+/*
+ * forks off sample_size processes and records the starting address of the
+ * indicated library as reported by exec_name.  Reports entropy observed among
+ * recorded samples.
+ */
+unsigned int calc_mmap_entropy(const char *exec_name, const char *lib_match, size_t samp_sz);
+
+#endif //ASLR_TEST_H
diff --git a/tests/kernel.config/logger_test.cpp b/tests/kernel.config/logger_test.cpp
new file mode 100644
index 0000000..f0874d8
--- /dev/null
+++ b/tests/kernel.config/logger_test.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+TEST(kernel_config, NOT_CONFIG_ANDROID_LOGGER) {
+  EXPECT_NE(0, access("/dev/log/main", F_OK));
+  EXPECT_NE(0, access("/dev/log_main", F_OK));
+  EXPECT_NE(0, access("/dev/log/radio", F_OK));
+  EXPECT_NE(0, access("/dev/log_radio", F_OK));
+  EXPECT_NE(0, access("/dev/log/events", F_OK));
+  EXPECT_NE(0, access("/dev/log_events", F_OK));
+  EXPECT_NE(0, access("/dev/log/system", F_OK));
+  EXPECT_NE(0, access("/dev/log_system", F_OK));
+}
diff --git a/tests/kernel.config/mmc_max_speed_test.cpp b/tests/kernel.config/mmc_max_speed_test.cpp
new file mode 100644
index 0000000..40cf0d0
--- /dev/null
+++ b/tests/kernel.config/mmc_max_speed_test.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+TEST(kernel_config, CONFIG_MMC_BLOCK_MAX_SPEED) {
+  EXPECT_EQ(0, access("/sys/block/mmcblk0/max_read_speed", F_OK));
+  EXPECT_EQ(0, access("/sys/block/mmcblk0/max_write_speed", F_OK));
+  EXPECT_EQ(0, access("/sys/block/mmcblk0/cache_size", F_OK));
+}
diff --git a/tests/kernel.config/multicast_test.cpp b/tests/kernel.config/multicast_test.cpp
new file mode 100644
index 0000000..28655e8
--- /dev/null
+++ b/tests/kernel.config/multicast_test.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+TEST(kernel_config, CONFIG_IPV6) {
+  EXPECT_EQ(0, access("/proc/net/igmp6", F_OK));
+}
+
+TEST(kernel_config, CONFIG_IP_MULTICAST) {
+  EXPECT_EQ(0, access("/proc/net/igmp", F_OK));
+}
diff --git a/tests/kernel.config/pstore_test.cpp b/tests/kernel.config/pstore_test.cpp
new file mode 100644
index 0000000..1dd5e72
--- /dev/null
+++ b/tests/kernel.config/pstore_test.cpp
@@ -0,0 +1,32 @@
+
+/*
+ * Copyright (C) 2016 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.
+ */
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+TEST(kernel_config, CONFIG_PSTORE) {
+  EXPECT_EQ(0, access("/sys/fs/pstore", F_OK));
+}
+
+TEST(kernel_config, CONFIG_PSTORE_CONSOLE) {
+  EXPECT_EQ(0, access("/sys/fs/pstore/console-ramoops", F_OK));
+}
+
+TEST(kernel_config, CONFIG_PSTORE_PMSG) {
+  EXPECT_EQ(0, access("/dev/pmsg0", F_OK));
+  EXPECT_EQ(0, access("/sys/fs/pstore/pmsg-ramoops-0", F_OK));
+}
diff --git a/tests/kernel.config/scrape_mmap_addr.cpp b/tests/kernel.config/scrape_mmap_addr.cpp
new file mode 100644
index 0000000..be5995f
--- /dev/null
+++ b/tests/kernel.config/scrape_mmap_addr.cpp
@@ -0,0 +1,32 @@
+#include <errno.h>
+#include <fstream>
+#include <iostream>
+#include <regex>
+#include <string>
+#include <string.h>
+
+int main(int argc, char * argv[]) {
+    if (argc != 2) {
+        std::cerr << "usage: " << argv[0] << ": libname\n";
+        return -1;
+    }
+    std::regex reg(std::string("^([a-f0-9]+)\\-[0-9a-f]+\\s+.+\\s+(\\d+)\\s+.+\\s+\\d+\\s+") + std::string(argv[1]) + std::string("\\s*$"));
+
+    /* open /proc/self/maps */
+    std::string ln;
+    std::ifstream m_file("/proc/self/maps");
+    if (!m_file) {
+        std::cerr << "Unable to open /proc/self/maps " << strerror(errno) << "\n";
+        return -1;
+    }
+    while (getline(m_file, ln)) {
+        std::smatch sm;
+        if (std::regex_match (ln,sm, reg)) {
+            if (std::stoi(sm[2]) == 0) {
+                std::cout << sm[1];
+                return 0;
+            }
+        }
+    }
+    return -1;
+}
diff --git a/tests/kernel.config/sysvipc_test.cpp b/tests/kernel.config/sysvipc_test.cpp
new file mode 100644
index 0000000..49952f0
--- /dev/null
+++ b/tests/kernel.config/sysvipc_test.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#include <errno.h>
+#ifdef HAS_KCMP
+#include <linux/kcmp.h>
+#include <sys/syscall.h>
+#endif
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#ifdef HAS_KCMP
+int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
+  return syscall(SYS_kcmp, pid1, pid2, type, 0, idx1, idx2);
+}
+#endif
+
+TEST(kernel_config, NOT_CONFIG_SYSVIPC) {
+#ifdef HAS_KCMP
+  pid_t pid = getpid();
+  int ret = kcmp(pid, pid, KCMP_SYSVSEM, 0, 0);
+  int error = (ret == -1) ? (errno == ENOSYS) ? EOPNOTSUPP : errno : 0;
+  EXPECT_EQ(-1, kcmp(pid, pid, KCMP_SYSVSEM, 0, 0));
+  EXPECT_EQ(EOPNOTSUPP, error);
+#endif
+  EXPECT_EQ(-1, access("/proc/sysvipc", F_OK));
+  EXPECT_EQ(-1, access("/proc/sysvipc/msg", F_OK));
+  EXPECT_EQ(-1, access("/proc/sysvipc/sem", F_OK));
+  EXPECT_EQ(-1, access("/proc/sysvipc/shm", F_OK));
+}
+
diff --git a/tests/lib/Android.mk b/tests/lib/Android.mk
new file mode 100644
index 0000000..db16ed2
--- /dev/null
+++ b/tests/lib/Android.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2010 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(call all-subdir-makefiles)
diff --git a/tests/lib/testUtil/Android.mk b/tests/lib/testUtil/Android.mk
new file mode 100644
index 0000000..f814dac
--- /dev/null
+++ b/tests/lib/testUtil/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2010 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE:= libtestUtil
+LOCAL_SRC_FILES:= testUtil.c
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../include
+LOCAL_CFLAGS += -std=c99
+LOCAL_SHARED_LIBRARIES += libcutils libutils
+
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/tests/lib/testUtil/testUtil.c b/tests/lib/testUtil/testUtil.c
new file mode 100644
index 0000000..d4dcea2
--- /dev/null
+++ b/tests/lib/testUtil/testUtil.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2010 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.
+ *
+ */
+
+#include <testUtil.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <cutils/log.h>
+
+#define ALEN(a) (sizeof(a) / sizeof((a)[0]))  // Array length
+typedef unsigned int bool_t;
+#define true (0 == 0)
+#define false (!true)
+
+#define MAXSTR 200
+
+static const char *logCatTag;
+static const unsigned int uSecsPerSec = 1000000;
+static const unsigned int nSecsPerSec = 1000000000;
+
+// struct timespec to double
+double ts2double(const struct timespec *val)
+{
+    double rv;
+
+    rv = val->tv_sec;
+    rv += (double) val->tv_nsec / nSecsPerSec;
+
+    return rv;
+}
+
+// struct timeval to double
+double tv2double(const struct timeval *val)
+{
+    double rv;
+
+    rv = val->tv_sec;
+    rv += (double) val->tv_usec / uSecsPerSec;
+
+    return rv;
+}
+
+// double to struct timespec
+struct timespec double2ts(double amt)
+{
+    struct timespec rv;
+
+    rv.tv_sec = floor(amt);
+    rv.tv_nsec = (amt - rv.tv_sec) * nSecsPerSec;
+    // TODO: Handle cases where amt is negative
+    while ((unsigned) rv.tv_nsec >= nSecsPerSec) {
+        rv.tv_nsec -= nSecsPerSec;
+        rv.tv_sec++;
+    }
+
+    return rv;
+}
+
+// double to struct timeval
+struct timeval double2tv(double amt)
+{
+    struct timeval rv;
+
+    rv.tv_sec = floor(amt);
+    rv.tv_usec = (amt - rv.tv_sec) * uSecsPerSec;
+    // TODO: Handle cases where amt is negative
+    while ((unsigned) rv.tv_usec >= uSecsPerSec) {
+        rv.tv_usec -= uSecsPerSec;
+        rv.tv_sec++;
+    }
+
+    return rv;
+}
+
+// Delta (difference) between two struct timespec.
+// It is expected that the time given by the structure pointed to by
+// second, is later than the time pointed to by first.
+struct timespec tsDelta(const struct timespec *first,
+                        const struct timespec *second)
+{
+    struct timespec rv;
+
+    assert(first != NULL);
+    assert(second != NULL);
+    assert(first->tv_nsec >= 0 && first->tv_nsec < nSecsPerSec);
+    assert(second->tv_nsec >= 0 && second->tv_nsec < nSecsPerSec);
+    rv.tv_sec = second->tv_sec - first->tv_sec;
+    if (second->tv_nsec >= first->tv_nsec) {
+        rv.tv_nsec = second->tv_nsec - first->tv_nsec;
+    } else {
+        rv.tv_nsec = (second->tv_nsec + nSecsPerSec) - first->tv_nsec;
+        rv.tv_sec--;
+    }
+
+    return rv;
+}
+
+// Delta (difference) between two struct timeval.
+// It is expected that the time given by the structure pointed to by
+// second, is later than the time pointed to by first.
+struct timeval tvDelta(const struct timeval *first,
+                       const struct timeval *second)
+{
+    struct timeval rv;
+
+    assert(first != NULL);
+    assert(second != NULL);
+    assert(first->tv_usec >= 0 && first->tv_usec < uSecsPerSec);
+    assert(second->tv_usec >= 0 && second->tv_usec < uSecsPerSec);
+    rv.tv_sec = second->tv_sec - first->tv_sec;
+    if (second->tv_usec >= first->tv_usec) {
+        rv.tv_usec = second->tv_usec - first->tv_usec;
+    } else {
+        rv.tv_usec = (second->tv_usec + uSecsPerSec) - first->tv_usec;
+        rv.tv_sec--;
+    }
+
+    return rv;
+}
+
+void testPrint(FILE *stream, const char *fmt, ...)
+{
+    char line[MAXSTR];
+    va_list args;
+
+    va_start(args, fmt);
+    vsnprintf(line, sizeof(line), fmt, args);
+    if (stream == stderr) {
+        ALOG(LOG_ERROR, logCatTag, "%s", line);
+    } else {
+        ALOG(LOG_INFO, logCatTag, "%s", line);
+    }
+    vfprintf(stream, fmt, args);
+    fputc('\n', stream);
+}
+
+// Set tag used while logging to the logcat error interface
+void testSetLogCatTag(const char *tag)
+{
+    logCatTag = tag;
+}
+
+// Obtain pointer to current log to logcat error interface tag
+const char * testGetLogCatTag(void)
+{
+    return logCatTag;
+}
+
+/*
+ * Random
+ *
+ * Returns a pseudo random number in the range [0:2^32-1].
+ *
+ * Precondition: srand48() called to set the seed of
+ *   the pseudo random number generator.
+ */
+uint32_t testRand(void)
+{
+    uint32_t val;
+
+    // Use lrand48() to obtain 31 bits worth
+    // of randomness.
+    val = lrand48();
+
+    // Make an additional lrand48() call and merge
+    // the randomness into the most significant bits.
+    val ^= lrand48() << 1;
+
+    return val;
+}
+
+/*
+ * Random Modulus
+ *
+ * Pseudo randomly returns unsigned integer in the range [0, mod).
+ *
+ * Precondition: srand48() called to set the seed of
+ *   the pseudo random number generator.
+ */
+uint32_t testRandMod(uint32_t mod)
+{
+    // Obtain the random value
+    // Use lrand48() when it would produce a sufficient
+    // number of random bits, otherwise use testRand().
+    const uint32_t lrand48maxVal = ((uint32_t) 1 << 31) - 1;
+    uint32_t val = (mod <= lrand48maxVal) ? (uint32_t) lrand48() : testRand();
+
+    /*
+     * The contents of individual bytes tend to be less than random
+     * across different seeds.  For example, srand48(x) and
+     * srand48(x + n * 4) cause lrand48() to return the same sequence of
+     * least significant bits.  For small mod values this can produce
+     * noticably non-random sequnces.  For mod values of less than 2
+     * bytes, will use the randomness from all the bytes.
+     */
+    if (mod <= 0x10000) {
+        val = (val & 0xffff) ^ (val >> 16);
+
+        // If mod less than a byte, can further combine down to
+        // a single byte.
+        if (mod <= 0x100) {
+            val = (val & 0xff) ^ (val >> 8);
+        }
+    }
+
+    return val % mod;
+}
+
+/*
+ * Random Boolean
+ *
+ * Pseudo randomly returns 0 (false) or 1 (true).
+ *
+ * Precondition: srand48() called to set the seed of
+ *   the pseudo random number generator.
+ */
+int testRandBool(void)
+{
+    return (testRandMod(2));
+}
+
+/*
+ * Random Fraction
+ *
+ * Pseudo randomly return a value in the range [0.0, 1.0).
+ *
+ * Precondition: srand48() called to set the seed of
+ *   the pseudo random number generator.
+ */
+double testRandFract(void)
+{
+    return drand48();
+}
+
+// Delays for the number of seconds specified by amt or a greater amount.
+// The amt variable is of type float and thus non-integer amounts
+// of time can be specified.  This function automatically handles cases
+// where nanosleep(2) returns early due to reception of a signal.
+void testDelay(float amt)
+{
+    struct timespec   start, current, delta;
+    struct timespec   remaining;
+
+    // Get the time at which we started
+    clock_gettime(CLOCK_MONOTONIC, &start);
+
+    do {
+        // Get current time
+        clock_gettime(CLOCK_MONOTONIC, &current);
+
+        // How much time is left
+        delta = tsDelta(&start, &current);
+        if (ts2double(&delta) > amt) { break; }
+
+        // Request to sleep for the remaining time
+        remaining = double2ts(amt - ts2double(&delta));
+        (void) nanosleep(&remaining, NULL);
+    } while (true);
+}
+
+// Delay spins for the number of seconds specified by amt or a greater
+// amount.  The amt variable is of type float and thus non-integer amounts
+// of time can be specified.  Differs from testDelay() in that
+// testDelaySpin() performs a spin loop, instead of using nanosleep().
+void testDelaySpin(float amt)
+{
+    struct timespec   start, current, delta;
+
+    // Get the time at which we started
+    clock_gettime(CLOCK_MONOTONIC, &start);
+
+    do {
+        // Get current time
+        clock_gettime(CLOCK_MONOTONIC, &current);
+
+        // How much time is left
+        delta = tsDelta(&start, &current);
+        if (ts2double(&delta) > amt) { break; }
+    } while (true);
+}
+
+/*
+ * Hex Dump
+ *
+ * Displays in hex the contents of the memory starting at the location
+ * pointed to by buf, for the number of bytes given by size.
+ * Each line of output is indented by a number of spaces that
+ * can be set by calling xDumpSetIndent().  It is also possible
+ * to offset the displayed address by an amount set by calling
+ * xDumpSetOffset.
+ */
+static uint8_t     xDumpIndent;
+static uint64_t    xDumpOffset;
+void
+testXDump(const void *buf, size_t size)
+{
+    const unsigned int bytesPerLine = 16;
+    int rv;
+    char line[MAXSTR];
+    const unsigned char *ptr = buf, *start = buf;
+    size_t num = size;
+    char *linep = line;
+
+    while (num) {
+        if (((ptr - start) % bytesPerLine) == 0) {
+            if (linep != line) {
+                testPrintE("%s", line);
+            }
+            linep = line;
+            rv = snprintf(linep, ALEN(line) - (linep - line),
+                "%*s%06llx:", xDumpIndent, "",
+                (long long) (ptr - start) + xDumpOffset);
+            linep += rv;
+        }
+
+        // Check that there is at least room for 4
+        // more characters.  The 4 characters being
+        // a space, 2 hex digits and the terminating
+        // '\0'.
+        assert((ALEN(line) - 4) >= (linep - line));
+        rv = snprintf(linep, ALEN(line) - (linep - line),
+            " %02x", *ptr++);
+        linep += rv;
+        num--;
+    }
+    if (linep != line) {
+        testPrintE("%s", line);
+    }
+}
+
+// Set an indent of spaces for each line of hex dump output
+void
+testXDumpSetIndent(uint8_t indent)
+{
+    xDumpIndent = indent;
+}
+
+// Obtain the current hex dump indent amount
+uint8_t
+testXDumpGetIndent(void)
+{
+    return xDumpIndent;
+}
+
+// Set the hex dump address offset amount
+void
+testXDumpSetOffset(uint64_t offset)
+{
+    xDumpOffset = offset;
+}
+
+// Get the current hex dump address offset amount
+uint64_t
+testXDumpGetOffset(void)
+{
+    return xDumpOffset;
+}
+
+/*
+ * Execute Command
+ *
+ * Executes the command pointed to by cmd.  Output from the
+ * executed command is captured and sent to LogCat Info.  Once
+ * the command has finished execution, it's exit status is captured
+ * and checked for an exit status of zero.  Any other exit status
+ * causes diagnostic information to be printed and an immediate
+ * testcase failure.
+ */
+void testExecCmd(const char *cmd)
+{
+    FILE *fp;
+    int rv;
+    int status;
+    char str[MAXSTR];
+
+    // Display command to be executed
+    testPrintI("cmd: %s", cmd);
+
+    // Execute the command
+    fflush(stdout);
+    if ((fp = popen(cmd, "r")) == NULL) {
+        testPrintE("execCmd popen failed, errno: %i", errno);
+        exit(100);
+    }
+
+    // Obtain and display each line of output from the executed command
+    while (fgets(str, sizeof(str), fp) != NULL) {
+        if ((strlen(str) > 1) && (str[strlen(str) - 1] == '\n')) {
+            str[strlen(str) - 1] = '\0';
+        }
+        testPrintI(" out: %s", str);
+    }
+
+    // Obtain and check return status of executed command.
+    // Fail on non-zero exit status
+    status = pclose(fp);
+    if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
+        testPrintE("Unexpected command failure");
+        testPrintE("  status: %#x", status);
+        if (WIFEXITED(status)) {
+            testPrintE("WEXITSTATUS: %i", WEXITSTATUS(status));
+        }
+        if (WIFSIGNALED(status)) {
+            testPrintE("WTERMSIG: %i", WTERMSIG(status));
+        }
+        exit(101);
+    }
+}
diff --git a/tests/memtest/Android.mk b/tests/memtest/Android.mk
new file mode 100644
index 0000000..90d6d83
--- /dev/null
+++ b/tests/memtest/Android.mk
@@ -0,0 +1,26 @@
+# Copyright 2006 The Android Open Source Project
+ifneq ($(filter $(TARGET_ARCH),arm arm64),)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    memtest.cpp \
+    fptest.cpp \
+    thumb.cpp \
+    bandwidth.cpp \
+
+LOCAL_MODULE := memtest
+LOCAL_MODULE_TAGS := debug
+LOCAL_CFLAGS += \
+    -fomit-frame-pointer \
+    -Wall \
+    -Werror \
+
+LOCAL_MULTILIB := 32
+
+LOCAL_SANITIZE := never
+
+include $(BUILD_EXECUTABLE)
+endif
diff --git a/tests/memtest/bandwidth.cpp b/tests/memtest/bandwidth.cpp
new file mode 100644
index 0000000..5ff6756
--- /dev/null
+++ b/tests/memtest/bandwidth.cpp
@@ -0,0 +1,465 @@
+/*
+ * 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.
+ */
+
+#include "bandwidth.h"
+
+#include <ctype.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <map>
+#include <vector>
+
+
+typedef struct {
+    const char *name;
+    bool int_type;
+} option_t;
+
+option_t bandwidth_opts[] = {
+    { "size", true },
+    { "num_warm_loops", true },
+    { "num_loops", true },
+    { "type", false },
+    { NULL, false },
+};
+
+option_t per_core_opts[] = {
+    { "size", true },
+    { "num_warm_loops", true},
+    { "num_loops", true },
+    { "type", false },
+    { NULL, false },
+};
+
+option_t multithread_opts[] = {
+    { "size", true },
+    { "num_warm_loops", true},
+    { "num_loops", true },
+    { "type", false },
+    { "num_threads", true },
+    { NULL, false },
+};
+
+typedef union {
+    int int_value;
+    const char *char_value;
+} arg_value_t;
+typedef std::map<const char*, arg_value_t> arg_t;
+
+bool processBandwidthOptions(int argc, char** argv, option_t options[],
+                             arg_t *values) {
+    for (int i = 1; i < argc; i++) {
+        if (argv[i][0] == '-' && argv[i][1] == '-' && !isdigit(argv[i][2])) {
+            char *arg = &argv[i][2];
+
+            for (int j = 0; options[j].name != NULL; j++) {
+                if (strcmp(arg, options[j].name) == 0) {
+                    const char *name = options[j].name;
+                    if (i == argc - 1) {
+                        printf("The option --%s requires an argument.\n", name);
+                        return false;
+                    }
+                    if (options[j].int_type) {
+                        (*values)[name].int_value = strtol(argv[++i], NULL, 0);
+                    } else {
+                        (*values)[name].char_value = argv[++i];
+                    }
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+BandwidthBenchmark *createBandwidthBenchmarkObject(arg_t values) {
+    BandwidthBenchmark *bench = NULL;
+
+    const char *name = values["type"].char_value;
+    size_t size = 0;
+    if (values.count("size") > 0) {
+        size = values["size"].int_value;
+    }
+    if (strcmp(name, "copy_ldrd_strd") == 0) {
+        bench = new CopyLdrdStrdBenchmark();
+    } else if (strcmp(name, "copy_ldmia_stmia") == 0) {
+        bench = new CopyLdmiaStmiaBenchmark();
+    } else if (strcmp(name, "copy_vld1_vst1") == 0) {
+        bench = new CopyVld1Vst1Benchmark();
+    } else if (strcmp(name, "copy_vldr_vstr") == 0) {
+        bench = new CopyVldrVstrBenchmark();
+    } else if (strcmp(name, "copy_vldmia_vstmia") == 0) {
+        bench = new CopyVldmiaVstmiaBenchmark();
+    } else if (strcmp(name, "memcpy") == 0) {
+        bench = new MemcpyBenchmark();
+    } else if (strcmp(name, "write_strd") == 0) {
+        bench = new WriteStrdBenchmark();
+    } else if (strcmp(name, "write_stmia") == 0) {
+        bench = new WriteStmiaBenchmark();
+    } else if (strcmp(name, "write_vst1") == 0) {
+        bench = new WriteVst1Benchmark();
+    } else if (strcmp(name, "write_vstr") == 0) {
+        bench = new WriteVstrBenchmark();
+    } else if (strcmp(name, "write_vstmia") == 0) {
+        bench = new WriteVstmiaBenchmark();
+    } else if (strcmp(name, "memset") == 0) {
+        bench = new MemsetBenchmark();
+    } else if (strcmp(name, "read_ldrd") == 0) {
+        bench = new ReadLdrdBenchmark();
+    } else if (strcmp(name, "read_ldmia") == 0) {
+        bench = new ReadLdmiaBenchmark();
+    } else if (strcmp(name, "read_vld1") == 0) {
+        bench = new ReadVld1Benchmark();
+    } else if (strcmp(name, "read_vldr") == 0) {
+        bench = new ReadVldrBenchmark();
+    } else if (strcmp(name, "read_vldmia") == 0) {
+        bench = new ReadVldmiaBenchmark();
+    } else {
+        printf("Unknown type name %s\n", name);
+        return NULL;
+    }
+
+    if (!bench->setSize(size)) {
+        printf("Failed to allocate buffers for benchmark.\n");
+        return NULL;
+    }
+
+    if (values.count("num_warm_loops") > 0) {
+        bench->set_num_loops(values["num_warm_loops"].int_value);
+    }
+    if (values.count("num_loops") > 0) {
+        bench->set_num_loops(values["num_loops"].int_value);
+    }
+
+    return bench;
+}
+
+bool getAvailCpus(std::vector<int> *cpu_list) {
+    cpu_set_t cpuset;
+
+    CPU_ZERO(&cpuset);
+    if (sched_getaffinity(0, sizeof(cpuset), &cpuset) != 0) {
+        perror("sched_getaffinity failed.");
+        return false;
+    }
+
+    for (int i = 0; i < CPU_SETSIZE; i++) {
+        if (CPU_ISSET(i, &cpuset)) {
+            cpu_list->push_back(i);
+        }
+    }
+
+    return true;
+}
+
+typedef struct {
+    int core;
+    BandwidthBenchmark *bench;
+    double  avg_mb;
+    volatile bool *run;
+} thread_arg_t;
+
+void *runBandwidthThread(void *data) {
+    thread_arg_t *arg = reinterpret_cast<thread_arg_t *>(data);
+
+    if (arg->core >= 0) {
+        cpu_set_t cpuset;
+        CPU_ZERO(&cpuset);
+        CPU_SET(arg->core, &cpuset);
+        if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
+            perror("sched_setaffinity failed");
+            return NULL;
+        }
+    }
+
+    // Spinloop waiting for the run variable to get set to true.
+    while (!*arg->run) {
+    }
+
+    double avg_mb = 0;
+    for (int run = 1; ; run++) {
+        arg->bench->run();
+        if (!*arg->run) {
+            // Throw away the last data point since it's possible not
+            // all of the threads are running at this point.
+            break;
+        }
+        avg_mb = (avg_mb/run) * (run-1) + arg->bench->mb_per_sec()/run;
+    }
+    arg->avg_mb = avg_mb;
+
+    return NULL;
+}
+
+bool processThreadArgs(int argc, char** argv, option_t options[],
+                       arg_t *values) {
+    // Use some smaller values for the number of loops.
+    (*values)["num_warm_loops"].int_value = 1000000;
+    (*values)["num_loops"].int_value = 10000000;
+
+    if (!processBandwidthOptions(argc, argv, options, values)) {
+        return false;
+    }
+    if (values->count("size") > 0 && ((*values)["size"].int_value % 64) != 0) {
+        printf("The size values must be a multiple of 64.\n");
+        return false;
+    }
+    if (values->count("type") == 0) {
+        printf("Must specify the type value.\n");
+        return false;
+    }
+
+    BandwidthBenchmark *bench = createBandwidthBenchmarkObject(*values);
+    if (!bench) {
+        return false;
+    }
+
+    if (setpriority(PRIO_PROCESS, 0, -20)) {
+        perror("Unable to raise priority of process.");
+        return false;
+    }
+
+    printf("Calculating optimum run time...\n");
+    nsecs_t t = system_time();
+    bench->run();
+    t = system_time() - t;
+    // Since this is only going to be running single threaded, assume that
+    // if the number is set to ten times this value, we should get at least
+    // a couple of samples per thread.
+    int run_time = int((t/1000000000.0)*10 + 0.5) + 5;
+
+    (*values)["run_time"].int_value = run_time;
+    (*values)["size"].int_value = bench->size();
+    (*values)["num_warm_loops"].int_value = bench->num_warm_loops();
+    (*values)["num_loops"].int_value = bench->num_loops();
+    delete bench;
+
+    return true;
+}
+
+bool runThreadedTest(thread_arg_t args[], int num_threads, int run_time) {
+    pthread_t threads[num_threads];
+    volatile bool run = false;
+
+    int rc;
+    for (int i = 0; i < num_threads; i++) {
+        args[i].run = &run;
+        rc = pthread_create(&threads[i], NULL, runBandwidthThread,
+                            (void*)&args[i]);
+        if (rc != 0) {
+            printf("Failed to launch thread %d\n", i);
+            return false;
+        }
+    }
+
+    // Kick start the threads.
+    run = true;
+
+    // Let the threads run.
+    sleep(run_time);
+
+    // Stop the threads.
+    run = false;
+
+    // Wait for the threads to complete.
+    for (int i = 0; i < num_threads; i++) {
+        rc = pthread_join(threads[i], NULL);
+        if (rc != 0) {
+            printf("Thread %d failed to join.\n", i);
+            return false;
+        }
+        printf("Thread %d: bandwidth using %s %0.2f MB/s\n", i,
+               args[i].bench->getName(), args[i].avg_mb);
+    }
+
+    return true;
+}
+
+int per_core_bandwidth(int argc, char** argv) {
+    arg_t values;
+    if (!processThreadArgs(argc, argv, per_core_opts, &values)) {
+        return -1;
+    }
+
+    std::vector<int> cpu_list;
+    if (!getAvailCpus(&cpu_list)) {
+        printf("Failed to get available cpu list.\n");
+        return -1;
+    }
+
+    thread_arg_t args[cpu_list.size()];
+
+    int i = 0;
+    for (std::vector<int>::iterator it = cpu_list.begin();
+         it != cpu_list.end(); ++it, ++i) {
+        args[i].core = *it;
+        args[i].bench = createBandwidthBenchmarkObject(values);
+        if (!args[i].bench) {
+            return -1;
+        }
+    }
+
+    printf("Running on %d cores\n", cpu_list.size());
+    printf("  run_time = %ds\n", values["run_time"].int_value);
+    printf("  size = %d\n", values["size"].int_value);
+    printf("  num_warm_loops = %d\n", values["num_warm_loops"].int_value);
+    printf("  num_loops = %d\n", values["num_loops"].int_value);
+    printf("\n");
+
+    if (!runThreadedTest(args, cpu_list.size(), values["run_time"].int_value)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int multithread_bandwidth(int argc, char** argv) {
+    arg_t values;
+    if (!processThreadArgs(argc, argv, multithread_opts, &values)) {
+        return -1;
+    }
+    if (values.count("num_threads") == 0) {
+        printf("Must specify the num_threads value.\n");
+        return -1;
+    }
+    int num_threads = values["num_threads"].int_value;
+
+    thread_arg_t args[num_threads];
+
+    for (int i = 0; i < num_threads; i++) {
+        args[i].core = -1;
+        args[i].bench = createBandwidthBenchmarkObject(values);
+        if (!args[i].bench) {
+            return -1;
+        }
+    }
+
+    printf("Running %d threads\n", num_threads);
+    printf("  run_time = %ds\n", values["run_time"].int_value);
+    printf("  size = %d\n", values["size"].int_value);
+    printf("  num_warm_loops = %d\n", values["num_warm_loops"].int_value);
+    printf("  num_loops = %d\n", values["num_loops"].int_value);
+    printf("\n");
+
+    if (!runThreadedTest(args, num_threads, values["run_time"].int_value)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+bool run_bandwidth_benchmark(int argc, char** argv, const char *name,
+                             std::vector<BandwidthBenchmark*> bench_objs) {
+    arg_t values;
+    values["size"].int_value = 0;
+    values["num_warm_loops"].int_value = 0;
+    values["num_loops"].int_value = 0;
+    if (!processBandwidthOptions(argc, argv, bandwidth_opts, &values)) {
+        return false;
+    }
+
+    size_t size = values["size"].int_value;
+    if ((size % 64) != 0) {
+        printf("The size value must be a multiple of 64.\n");
+        return false;
+    }
+
+    if (setpriority(PRIO_PROCESS, 0, -20)) {
+        perror("Unable to raise priority of process.");
+        return false;
+    }
+
+    bool preamble_printed = false;
+    size_t num_warm_loops = values["num_warm_loops"].int_value;
+    size_t num_loops = values["num_loops"].int_value;
+    for (std::vector<BandwidthBenchmark*>::iterator it = bench_objs.begin();
+         it != bench_objs.end(); ++it) {
+        if (!(*it)->canRun()) {
+            continue;
+        }
+        if (!(*it)->setSize(values["size"].int_value)) {
+            printf("Failed creating buffer for bandwidth test.\n");
+            return false;
+        }
+        if (num_warm_loops) {
+            (*it)->set_num_warm_loops(num_warm_loops);
+        }
+        if (num_loops) {
+            (*it)->set_num_loops(num_loops);
+        }
+        if (!preamble_printed) {
+            preamble_printed = true;
+            printf("Benchmarking %s bandwidth\n", name);
+            printf("  size = %d\n", (*it)->size());
+            printf("  num_warm_loops = %d\n", (*it)->num_warm_loops());
+            printf("  num_loops = %d\n\n", (*it)->num_loops());
+        }
+        (*it)->run();
+        printf("  %s bandwidth with %s: %0.2f MB/s\n", name, (*it)->getName(),
+               (*it)->mb_per_sec());
+    }
+
+    return true;
+}
+
+int copy_bandwidth(int argc, char** argv) {
+    std::vector<BandwidthBenchmark*> bench_objs;
+    bench_objs.push_back(new CopyLdrdStrdBenchmark());
+    bench_objs.push_back(new CopyLdmiaStmiaBenchmark());
+    bench_objs.push_back(new CopyVld1Vst1Benchmark());
+    bench_objs.push_back(new CopyVldrVstrBenchmark());
+    bench_objs.push_back(new CopyVldmiaVstmiaBenchmark());
+    bench_objs.push_back(new MemcpyBenchmark());
+
+    if (!run_bandwidth_benchmark(argc, argv, "copy", bench_objs)) {
+        return -1;
+    }
+    return 0;
+}
+
+int write_bandwidth(int argc, char** argv) {
+    std::vector<BandwidthBenchmark*> bench_objs;
+    bench_objs.push_back(new WriteStrdBenchmark());
+    bench_objs.push_back(new WriteStmiaBenchmark());
+    bench_objs.push_back(new WriteVst1Benchmark());
+    bench_objs.push_back(new WriteVstrBenchmark());
+    bench_objs.push_back(new WriteVstmiaBenchmark());
+    bench_objs.push_back(new MemsetBenchmark());
+
+    if (!run_bandwidth_benchmark(argc, argv, "write", bench_objs)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int read_bandwidth(int argc, char** argv) {
+    std::vector<BandwidthBenchmark*> bench_objs;
+    bench_objs.push_back(new ReadLdrdBenchmark());
+    bench_objs.push_back(new ReadLdmiaBenchmark());
+    bench_objs.push_back(new ReadVld1Benchmark());
+    bench_objs.push_back(new ReadVldrBenchmark());
+    bench_objs.push_back(new ReadVldmiaBenchmark());
+
+    if (!run_bandwidth_benchmark(argc, argv, "read", bench_objs)) {
+        return -1;
+    }
+    return 0;
+}
diff --git a/tests/memtest/bandwidth.h b/tests/memtest/bandwidth.h
new file mode 100644
index 0000000..b43349c
--- /dev/null
+++ b/tests/memtest/bandwidth.h
@@ -0,0 +1,940 @@
+/*
+ * 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 __BANDWIDTH_H__
+#define __BANDWIDTH_H__
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils/Compat.h"
+#include "memtest.h"
+
+// Bandwidth Class definitions.
+class BandwidthBenchmark {
+public:
+    BandwidthBenchmark()
+        : _size(0),
+          _num_warm_loops(DEFAULT_NUM_WARM_LOOPS),
+          _num_loops(DEFAULT_NUM_LOOPS) {}
+    virtual ~BandwidthBenchmark() {}
+
+    bool run() {
+        if (_size == 0) {
+            return false;
+        }
+        if (!canRun()) {
+            return false;
+        }
+
+        bench(_num_warm_loops);
+
+        nsecs_t t = system_time();
+        bench(_num_loops);
+        t = system_time() - t;
+
+        _mb_per_sec = (_size*(_num_loops/_BYTES_PER_MB))/(t/_NUM_NS_PER_SEC);
+
+        return true;
+    }
+
+    bool canRun() { return !usesNeon() || isNeonSupported(); }
+
+    virtual bool setSize(size_t size) = 0;
+
+    virtual const char *getName() = 0;
+
+    virtual bool verify() = 0;
+
+    virtual bool usesNeon() { return false; }
+
+    bool isNeonSupported() {
+#if defined(__ARM_NEON__)
+        return true;
+#else
+        return false;
+#endif
+    }
+
+    // Accessors/mutators.
+    double mb_per_sec() { return _mb_per_sec; }
+    size_t num_warm_loops() { return _num_warm_loops; }
+    size_t num_loops() { return _num_loops; }
+    size_t size() { return _size; }
+
+    void set_num_warm_loops(size_t num_warm_loops) {
+        _num_warm_loops = num_warm_loops;
+    }
+    void set_num_loops(size_t num_loops) { _num_loops = num_loops; }
+
+    // Static constants
+    static const unsigned int DEFAULT_NUM_WARM_LOOPS = 1000000;
+    static const unsigned int DEFAULT_NUM_LOOPS = 20000000;
+
+protected:
+    virtual void bench(size_t num_loops) = 0;
+
+    double _mb_per_sec;
+    size_t _size;
+    size_t _num_warm_loops;
+    size_t _num_loops;
+
+private:
+    // Static constants
+    static const CONSTEXPR double _NUM_NS_PER_SEC = 1000000000.0;
+    static const CONSTEXPR double _BYTES_PER_MB = 1024.0* 1024.0;
+};
+
+class CopyBandwidthBenchmark : public BandwidthBenchmark {
+public:
+    CopyBandwidthBenchmark() : BandwidthBenchmark(), _src(NULL), _dst(NULL) { }
+
+    bool setSize(size_t size) {
+        if (_src) {
+           free(_src);
+        }
+        if (_dst) {
+            free(_dst);
+        }
+
+        if (size == 0) {
+            _size = DEFAULT_COPY_SIZE;
+        } else {
+            _size = size;
+        }
+
+        _src = reinterpret_cast<char*>(memalign(64, _size));
+        if (!_src) {
+            perror("Failed to allocate memory for test.");
+            return false;
+        }
+        _dst = reinterpret_cast<char*>(memalign(64, _size));
+        if (!_dst) {
+            perror("Failed to allocate memory for test.");
+            return false;
+        }
+
+        return true;
+    }
+    virtual ~CopyBandwidthBenchmark() {
+        if (_src) {
+            free(_src);
+            _src = NULL;
+        }
+        if (_dst) {
+            free(_dst);
+            _dst = NULL;
+        }
+    }
+
+    bool verify() {
+        memset(_src, 0x23, _size);
+        memset(_dst, 0, _size);
+        bench(1);
+        if (memcmp(_src, _dst, _size) != 0) {
+            printf("Buffers failed to compare after one loop.\n");
+            return false;
+        }
+
+        memset(_src, 0x23, _size);
+        memset(_dst, 0, _size);
+        _num_loops = 2;
+        bench(2);
+        if (memcmp(_src, _dst, _size) != 0) {
+            printf("Buffers failed to compare after two loops.\n");
+            return false;
+        }
+
+        return true;
+    }
+
+protected:
+    char *_src;
+    char *_dst;
+
+    static const unsigned int DEFAULT_COPY_SIZE = 8000;
+};
+
+class CopyLdrdStrdBenchmark : public CopyBandwidthBenchmark {
+public:
+    CopyLdrdStrdBenchmark() : CopyBandwidthBenchmark() { }
+    virtual ~CopyLdrdStrdBenchmark() {}
+
+    const char *getName() { return "ldrd/strd"; }
+
+protected:
+    // Copy using ldrd/strd instructions.
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3,r4,r6,r7}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+            "mov r3, %3\n"
+
+            "0:\n"
+            "mov r4, r2, lsr #6\n"
+
+            "1:\n"
+            "ldrd r6, r7, [r0]\n"
+            "strd r6, r7, [r1]\n"
+            "ldrd r6, r7, [r0, #8]\n"
+            "strd r6, r7, [r1, #8]\n"
+            "ldrd r6, r7, [r0, #16]\n"
+            "strd r6, r7, [r1, #16]\n"
+            "ldrd r6, r7, [r0, #24]\n"
+            "strd r6, r7, [r1, #24]\n"
+            "ldrd r6, r7, [r0, #32]\n"
+            "strd r6, r7, [r1, #32]\n"
+            "ldrd r6, r7, [r0, #40]\n"
+            "strd r6, r7, [r1, #40]\n"
+            "ldrd r6, r7, [r0, #48]\n"
+            "strd r6, r7, [r1, #48]\n"
+            "ldrd r6, r7, [r0, #56]\n"
+            "strd r6, r7, [r1, #56]\n"
+
+            "add  r0, r0, #64\n"
+            "add  r1, r1, #64\n"
+            "subs r4, r4, #1\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r2\n"
+            "sub r1, r1, r2\n"
+            "subs r3, r3, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3,r4,r6,r7}\n"
+        :: "r" (_src), "r" (_dst), "r" (_size), "r" (num_loops) : "r0", "r1", "r2", "r3");
+    }
+};
+
+class CopyLdmiaStmiaBenchmark : public CopyBandwidthBenchmark {
+public:
+    CopyLdmiaStmiaBenchmark() : CopyBandwidthBenchmark() { }
+    virtual ~CopyLdmiaStmiaBenchmark() {}
+
+    const char *getName() { return "ldmia/stmia"; }
+
+protected:
+    // Copy using ldmia/stmia instructions.
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+            "mov r3, %3\n"
+
+            "0:\n"
+            "mov r4, r2, lsr #6\n"
+
+            "1:\n"
+            "ldmia r0!, {r5, r6, r7, r8, r9, r10, r11, r12}\n"
+            "stmia r1!, {r5, r6, r7, r8, r9, r10, r11, r12}\n"
+            "subs r4, r4, #1\n"
+            "ldmia r0!, {r5, r6, r7, r8, r9, r10, r11, r12}\n"
+            "stmia r1!, {r5, r6, r7, r8, r9, r10, r11, r12}\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r2\n"
+            "sub r1, r1, r2\n"
+            "subs r3, r3, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12}\n"
+        :: "r" (_src), "r" (_dst), "r" (_size), "r" (num_loops) : "r0", "r1", "r2", "r3");
+    }
+};
+
+class CopyVld1Vst1Benchmark : public CopyBandwidthBenchmark {
+public:
+    CopyVld1Vst1Benchmark() : CopyBandwidthBenchmark() { }
+    virtual ~CopyVld1Vst1Benchmark() {}
+
+    const char *getName() { return "vld1/vst1"; }
+
+    bool usesNeon() { return true; }
+
+protected:
+    // Copy using vld1/vst1 instructions.
+#if defined(__ARM_NEON__)
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3,r4}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+            "mov r3, %3\n"
+
+            "0:\n"
+            "mov r4, r2, lsr #6\n"
+
+            "1:\n"
+            "vld1.8 {d0-d3}, [r0]!\n"
+            "vld1.8 {d4-d7}, [r0]!\n"
+            "subs r4, r4, #1\n"
+            "vst1.8 {d0-d3}, [r1:128]!\n"
+            "vst1.8 {d4-d7}, [r1:128]!\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r2\n"
+            "sub r1, r1, r2\n"
+            "subs r3, r3, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3,r4}\n"
+        :: "r" (_src), "r" (_dst), "r" (_size), "r" (num_loops) : "r0", "r1", "r2", "r3");
+#else
+    void bench(size_t) {
+#endif
+    }
+};
+
+class CopyVldrVstrBenchmark : public CopyBandwidthBenchmark {
+public:
+    CopyVldrVstrBenchmark() : CopyBandwidthBenchmark() { }
+    virtual ~CopyVldrVstrBenchmark() {}
+
+    const char *getName() { return "vldr/vstr"; }
+
+    bool usesNeon() { return true; }
+
+protected:
+    // Copy using vldr/vstr instructions.
+#if defined(__ARM_NEON__)
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3,r4}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+            "mov r3, %3\n"
+
+            "0:\n"
+            "mov r4, r2, lsr #6\n"
+
+            "1:\n"
+            "vldr d0, [r0, #0]\n"
+            "subs r4, r4, #1\n"
+            "vldr d1, [r0, #8]\n"
+            "vstr d0, [r1, #0]\n"
+            "vldr d0, [r0, #16]\n"
+            "vstr d1, [r1, #8]\n"
+            "vldr d1, [r0, #24]\n"
+            "vstr d0, [r1, #16]\n"
+            "vldr d0, [r0, #32]\n"
+            "vstr d1, [r1, #24]\n"
+            "vldr d1, [r0, #40]\n"
+            "vstr d0, [r1, #32]\n"
+            "vldr d0, [r0, #48]\n"
+            "vstr d1, [r1, #40]\n"
+            "vldr d1, [r0, #56]\n"
+            "vstr d0, [r1, #48]\n"
+            "add r0, r0, #64\n"
+            "vstr d1, [r1, #56]\n"
+            "add r1, r1, #64\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r2\n"
+            "sub r1, r1, r2\n"
+            "subs r3, r3, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3,r4}\n"
+        :: "r" (_src), "r" (_dst), "r" (_size), "r" (num_loops) : "r0", "r1", "r2", "r3");
+#else
+    void bench(size_t) {
+#endif
+    }
+};
+
+class CopyVldmiaVstmiaBenchmark : public CopyBandwidthBenchmark {
+public:
+    CopyVldmiaVstmiaBenchmark() : CopyBandwidthBenchmark() { }
+    virtual ~CopyVldmiaVstmiaBenchmark() {}
+
+    const char *getName() { return "vldmia/vstmia"; }
+
+    bool usesNeon() { return true; }
+
+protected:
+    // Copy using vldmia/vstmia instructions.
+#if defined(__ARM_NEON__)
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3,r4}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+            "mov r3, %3\n"
+
+            "0:\n"
+            "mov r4, r2, lsr #6\n"
+
+            "1:\n"
+            "vldmia r0!, {d0-d7}\n"
+            "subs r4, r4, #1\n"
+            "vstmia r1!, {d0-d7}\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r2\n"
+            "sub r1, r1, r2\n"
+            "subs r3, r3, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3,r4}\n"
+        :: "r" (_src), "r" (_dst), "r" (_size), "r" (num_loops) : "r0", "r1", "r2", "r3");
+#else
+    void bench(size_t) {
+#endif
+    }
+};
+
+class MemcpyBenchmark : public CopyBandwidthBenchmark {
+public:
+    MemcpyBenchmark() : CopyBandwidthBenchmark() { }
+    virtual ~MemcpyBenchmark() {}
+
+    const char *getName() { return "memcpy"; }
+
+protected:
+    void bench(size_t num_loops) {
+        for (size_t i = 0; i < num_loops; i++) {
+            memcpy(_dst, _src, _size);
+        }
+    }
+};
+
+class SingleBufferBandwidthBenchmark : public BandwidthBenchmark {
+public:
+    SingleBufferBandwidthBenchmark() : BandwidthBenchmark(), _buffer(NULL) { }
+    virtual ~SingleBufferBandwidthBenchmark() {
+        if (_buffer) {
+            free(_buffer);
+            _buffer = NULL;
+        }
+    }
+
+    bool setSize(size_t size) {
+        if (_buffer) {
+            free(_buffer);
+            _buffer = NULL;
+        }
+
+        if (size == 0) {
+            _size = DEFAULT_SINGLE_BUFFER_SIZE;
+        } else {
+            _size = size;
+        }
+
+        _buffer = reinterpret_cast<char*>(memalign(64, _size));
+        if (!_buffer) {
+            perror("Failed to allocate memory for test.");
+            return false;
+        }
+        memset(_buffer, 0, _size);
+
+        return true;
+    }
+
+    bool verify() { return true; }
+
+protected:
+    char *_buffer;
+
+    static const unsigned int DEFAULT_SINGLE_BUFFER_SIZE = 16000;
+};
+
+class WriteBandwidthBenchmark : public SingleBufferBandwidthBenchmark {
+public:
+    WriteBandwidthBenchmark() : SingleBufferBandwidthBenchmark() { }
+    virtual ~WriteBandwidthBenchmark() { }
+
+    bool verify() {
+        memset(_buffer, 0, _size);
+        bench(1);
+        for (size_t i = 0; i < _size; i++) {
+            if (_buffer[i] != 1) {
+                printf("Buffer failed to compare after one loop.\n");
+                return false;
+            }
+        }
+
+        memset(_buffer, 0, _size);
+        bench(2);
+        for (size_t i = 0; i < _size; i++) {
+            if (_buffer[i] != 2) {
+                printf("Buffer failed to compare after two loops.\n");
+                return false;
+            }
+        }
+
+        return true;
+    }
+};
+
+class WriteStrdBenchmark : public WriteBandwidthBenchmark {
+public:
+    WriteStrdBenchmark() : WriteBandwidthBenchmark() { }
+    virtual ~WriteStrdBenchmark() {}
+
+    const char *getName() { return "strd"; }
+
+protected:
+    // Write a given value using strd.
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3,r4,r5}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+
+            "mov r4, #0\n"
+            "mov r5, #0\n"
+
+            "0:\n"
+            "mov r3, r1, lsr #5\n"
+
+            "add r4, r4, #0x01010101\n"
+            "mov r5, r4\n"
+
+            "1:\n"
+            "subs r3, r3, #1\n"
+            "strd r4, r5, [r0]\n"
+            "strd r4, r5, [r0, #8]\n"
+            "strd r4, r5, [r0, #16]\n"
+            "strd r4, r5, [r0, #24]\n"
+            "add  r0, r0, #32\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r1\n"
+            "subs r2, r2, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3,r4,r5}\n"
+          :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+    }
+};
+
+class WriteStmiaBenchmark : public WriteBandwidthBenchmark {
+public:
+    WriteStmiaBenchmark() : WriteBandwidthBenchmark() { }
+    virtual ~WriteStmiaBenchmark() {}
+
+    const char *getName() { return "stmia"; }
+
+protected:
+      // Write a given value using stmia.
+      void bench(size_t num_loops) {
+          asm volatile(
+              "stmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11}\n"
+
+              "mov r0, %0\n"
+              "mov r1, %1\n"
+              "mov r2, %2\n"
+
+              "mov r4, #0\n"
+
+              "0:\n"
+              "mov r3, r1, lsr #5\n"
+
+              "add r4, r4, #0x01010101\n"
+              "mov r5, r4\n"
+              "mov r6, r4\n"
+              "mov r7, r4\n"
+              "mov r8, r4\n"
+              "mov r9, r4\n"
+              "mov r10, r4\n"
+              "mov r11, r4\n"
+
+              "1:\n"
+              "subs r3, r3, #1\n"
+              "stmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
+              "bgt 1b\n"
+
+              "sub r0, r0, r1\n"
+              "subs r2, r2, #1\n"
+              "bgt 0b\n"
+
+              "ldmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11}\n"
+        :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+    }
+};
+
+class WriteVst1Benchmark : public WriteBandwidthBenchmark {
+public:
+    WriteVst1Benchmark() : WriteBandwidthBenchmark() { }
+    virtual ~WriteVst1Benchmark() {}
+
+    const char *getName() { return "vst1"; }
+
+    bool usesNeon() { return true; }
+
+protected:
+    // Write a given value using vst.
+#if defined(__ARM_NEON__)
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3,r4}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+            "mov r4, #0\n"
+
+            "0:\n"
+            "mov r3, r1, lsr #5\n"
+
+            "add r4, r4, #1\n"
+            "vdup.8 d0, r4\n"
+            "vmov d1, d0\n"
+            "vmov d2, d0\n"
+            "vmov d3, d0\n"
+
+            "1:\n"
+            "subs r3, r3, #1\n"
+            "vst1.8 {d0-d3}, [r0:128]!\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r1\n"
+            "subs r2, r2, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3,r4}\n"
+        :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+#else
+    void bench(size_t) {
+#endif
+    }
+};
+
+class WriteVstrBenchmark : public WriteBandwidthBenchmark {
+public:
+    WriteVstrBenchmark() : WriteBandwidthBenchmark() { }
+    virtual ~WriteVstrBenchmark() {}
+
+    const char *getName() { return "vstr"; }
+
+    bool usesNeon() { return true; }
+
+protected:
+    // Write a given value using vst.
+#if defined(__ARM_NEON__)
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3,r4}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+            "mov r4, #0\n"
+
+            "0:\n"
+            "mov r3, r1, lsr #5\n"
+
+            "add r4, r4, #1\n"
+            "vdup.8 d0, r4\n"
+            "vmov d1, d0\n"
+            "vmov d2, d0\n"
+            "vmov d3, d0\n"
+
+            "1:\n"
+            "vstr d0, [r0, #0]\n"
+            "subs r3, r3, #1\n"
+            "vstr d1, [r0, #8]\n"
+            "vstr d0, [r0, #16]\n"
+            "vstr d1, [r0, #24]\n"
+            "add r0, r0, #32\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r1\n"
+            "subs r2, r2, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3,r4}\n"
+        :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+#else
+    void bench(size_t) {
+#endif
+    }
+};
+
+class WriteVstmiaBenchmark : public WriteBandwidthBenchmark {
+public:
+    WriteVstmiaBenchmark() : WriteBandwidthBenchmark() { }
+    virtual ~WriteVstmiaBenchmark() {}
+
+    const char *getName() { return "vstmia"; }
+
+    bool usesNeon() { return true; }
+
+protected:
+    // Write a given value using vstmia.
+#if defined(__ARM_NEON__)
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3,r4}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+            "mov r4, #0\n"
+
+            "0:\n"
+            "mov r3, r1, lsr #5\n"
+
+            "add r4, r4, #1\n"
+            "vdup.8 d0, r4\n"
+            "vmov d1, d0\n"
+            "vmov d2, d0\n"
+            "vmov d3, d0\n"
+
+            "1:\n"
+            "subs r3, r3, #1\n"
+            "vstmia r0!, {d0-d3}\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r1\n"
+            "subs r2, r2, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3,r4}\n"
+        :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+#else
+    void bench(size_t) {
+#endif
+    }
+};
+
+class MemsetBenchmark : public WriteBandwidthBenchmark {
+public:
+    MemsetBenchmark() : WriteBandwidthBenchmark() { }
+    virtual ~MemsetBenchmark() {}
+
+    const char *getName() { return "memset"; }
+
+protected:
+    void bench(size_t num_loops) {
+        for (size_t i = 0; i < num_loops; i++) {
+            memset(_buffer, (i % 255) + 1, _size);
+        }
+    }
+};
+
+class ReadLdrdBenchmark : public SingleBufferBandwidthBenchmark {
+public:
+    ReadLdrdBenchmark() : SingleBufferBandwidthBenchmark() { }
+    virtual ~ReadLdrdBenchmark() {}
+
+    const char *getName() { return "ldrd"; }
+
+protected:
+    // Write a given value using strd.
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3,r4,r5}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+
+            "0:\n"
+            "mov r3, r1, lsr #5\n"
+
+            "1:\n"
+            "subs r3, r3, #1\n"
+            "ldrd r4, r5, [r0]\n"
+            "ldrd r4, r5, [r0, #8]\n"
+            "ldrd r4, r5, [r0, #16]\n"
+            "ldrd r4, r5, [r0, #24]\n"
+            "add  r0, r0, #32\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r1\n"
+            "subs r2, r2, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3,r4,r5}\n"
+          :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+    }
+};
+
+class ReadLdmiaBenchmark : public SingleBufferBandwidthBenchmark {
+public:
+    ReadLdmiaBenchmark() : SingleBufferBandwidthBenchmark() { }
+    virtual ~ReadLdmiaBenchmark() {}
+
+    const char *getName() { return "ldmia"; }
+
+protected:
+      // Write a given value using stmia.
+      void bench(size_t num_loops) {
+          asm volatile(
+              "stmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11}\n"
+
+              "mov r0, %0\n"
+              "mov r1, %1\n"
+              "mov r2, %2\n"
+
+              "0:\n"
+              "mov r3, r1, lsr #5\n"
+
+              "1:\n"
+              "subs r3, r3, #1\n"
+              "ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
+              "bgt 1b\n"
+
+              "sub r0, r0, r1\n"
+              "subs r2, r2, #1\n"
+              "bgt 0b\n"
+
+              "ldmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11}\n"
+        :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+    }
+};
+
+class ReadVld1Benchmark : public SingleBufferBandwidthBenchmark {
+public:
+    ReadVld1Benchmark() : SingleBufferBandwidthBenchmark() { }
+    virtual ~ReadVld1Benchmark() {}
+
+    const char *getName() { return "vld1"; }
+
+    bool usesNeon() { return true; }
+
+protected:
+    // Write a given value using vst.
+#if defined(__ARM_NEON__)
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+
+            "0:\n"
+            "mov r3, r1, lsr #5\n"
+
+            "1:\n"
+            "subs r3, r3, #1\n"
+            "vld1.8 {d0-d3}, [r0:128]!\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r1\n"
+            "subs r2, r2, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3}\n"
+        :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+#else
+    void bench(size_t) {
+#endif
+    }
+};
+
+class ReadVldrBenchmark : public SingleBufferBandwidthBenchmark {
+public:
+    ReadVldrBenchmark() : SingleBufferBandwidthBenchmark() { }
+    virtual ~ReadVldrBenchmark() {}
+
+    const char *getName() { return "vldr"; }
+
+    bool usesNeon() { return true; }
+
+protected:
+    // Write a given value using vst.
+#if defined(__ARM_NEON__)
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+
+            "0:\n"
+            "mov r3, r1, lsr #5\n"
+
+            "1:\n"
+            "vldr d0, [r0, #0]\n"
+            "subs r3, r3, #1\n"
+            "vldr d1, [r0, #8]\n"
+            "vldr d0, [r0, #16]\n"
+            "vldr d1, [r0, #24]\n"
+            "add r0, r0, #32\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r1\n"
+            "subs r2, r2, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3}\n"
+        :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+#else
+    void bench(size_t) {
+#endif
+    }
+};
+
+
+class ReadVldmiaBenchmark : public SingleBufferBandwidthBenchmark {
+public:
+    ReadVldmiaBenchmark() : SingleBufferBandwidthBenchmark() { }
+    virtual ~ReadVldmiaBenchmark() {}
+
+    const char *getName() { return "vldmia"; }
+
+    bool usesNeon() { return true; }
+
+protected:
+    // Write a given value using vstmia.
+#if defined(__ARM_NEON__)
+    void bench(size_t num_loops) {
+        asm volatile(
+            "stmfd sp!, {r0,r1,r2,r3}\n"
+
+            "mov r0, %0\n"
+            "mov r1, %1\n"
+            "mov r2, %2\n"
+
+            "0:\n"
+            "mov r3, r1, lsr #5\n"
+
+            "1:\n"
+            "subs r3, r3, #1\n"
+            "vldmia r0!, {d0-d3}\n"
+            "bgt 1b\n"
+
+            "sub r0, r0, r1\n"
+            "subs r2, r2, #1\n"
+            "bgt 0b\n"
+
+            "ldmfd sp!, {r0,r1,r2,r3}\n"
+        :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+#else
+    void bench(size_t) {
+#endif
+    }
+};
+
+#endif  // __BANDWIDTH_H__
diff --git a/tests/memtest/fptest.cpp b/tests/memtest/fptest.cpp
new file mode 100644
index 0000000..1ae04b2
--- /dev/null
+++ b/tests/memtest/fptest.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#ifdef __ARM_NEON__
+#include <arm_neon.h>
+#endif
+
+
+typedef long long nsecs_t;
+static nsecs_t gTime;
+float data_f[1024 * 128];
+
+static nsecs_t system_time()
+{
+    struct timespec t;
+    t.tv_sec = t.tv_nsec = 0;
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+}
+
+static void startTime()
+{
+    gTime = system_time();
+}
+
+static void endTime(const char *str, double ops)
+{
+    nsecs_t t = system_time() - gTime;
+    double ds = ((double)t) / 1e9;
+    printf("Test: %s, %f Mops\n", str, ops / ds / 1e6);
+}
+
+
+static void test_mad() {
+    for(int i=0; i<1020; i++) {
+        data_f[i] = i;
+    }
+
+    startTime();
+
+    // Do ~1 billion ops
+    for (int ct=0; ct < (1000 * (1000 / 20)); ct++) {
+        for (int i=0; i < 1000; i++) {
+            data_f[i] = (data_f[i] * 0.02f +
+                         data_f[i+1] * 0.04f +
+                         data_f[i+2] * 0.05f +
+                         data_f[i+3] * 0.1f +
+                         data_f[i+4] * 0.2f +
+                         data_f[i+5] * 0.2f +
+                         data_f[i+6] * 0.1f +
+                         data_f[i+7] * 0.05f +
+                         data_f[i+8] * 0.04f +
+                         data_f[i+9] * 0.02f + 1.f);
+        }
+    }
+
+    endTime("scalar mad", 1e9);
+}
+
+
+#ifdef __ARM_NEON__
+
+static void test_fma() {
+    for(int i=0; i<1020 * 4; i++) {
+        data_f[i] = i;
+    }
+    float32x4_t c0_02 = vdupq_n_f32(0.02f);
+    float32x4_t c0_04 = vdupq_n_f32(0.04f);
+    float32x4_t c0_05 = vdupq_n_f32(0.05f);
+    float32x4_t c0_10 = vdupq_n_f32(0.1f);
+    float32x4_t c0_20 = vdupq_n_f32(0.2f);
+    float32x4_t c1_00 = vdupq_n_f32(1.0f);
+
+    startTime();
+
+    // Do ~1 billion ops
+    for (int ct=0; ct < (1000 * (1000 / 80)); ct++) {
+        for (int i=0; i < 1000; i++) {
+            float32x4_t t;
+            t = vmulq_f32(vld1q_f32((float32_t *)&data_f[i]), c0_02);
+            t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+4]), c0_04);
+            t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+8]), c0_05);
+            t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+12]), c0_10);
+            t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+16]), c0_20);
+            t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+20]), c0_20);
+            t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+24]), c0_10);
+            t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+28]), c0_05);
+            t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+32]), c0_04);
+            t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+36]), c0_02);
+            t = vaddq_f32(t, c1_00);
+            vst1q_f32((float32_t *)&data_f[i], t);
+        }
+    }
+
+    endTime("neon fma", 1e9);
+}
+#endif
+
+int fp_test(int, char**) {
+    test_mad();
+
+#ifdef __ARM_NEON__
+    test_fma();
+#endif
+
+    return 0;
+}
diff --git a/tests/memtest/memtest.cpp b/tests/memtest/memtest.cpp
new file mode 100644
index 0000000..bad9209
--- /dev/null
+++ b/tests/memtest/memtest.cpp
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include "memtest.h"
+
+nsecs_t system_time() {
+    struct timespec t;
+    t.tv_sec = t.tv_nsec = 0;
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+}
+
+static void usage(char* p) {
+    printf("Usage: %s <test> <options>\n"
+           "<test> is one of the following:\n"
+           "  copy_bandwidth [--size BYTES_TO_COPY]\n"
+           "  write_bandwidth [--size BYTES_TO_WRITE]\n"
+           "  read_bandwidth [--size BYTES_TO_COPY]\n"
+           "  per_core_bandwidth [--size BYTES]\n"
+           "    --type copy_ldrd_strd | copy_ldmia_stmia | copy_vld1_vst1 |\n"
+           "           copy_vldr_vstr | copy_vldmia_vstmia | memcpy | write_strd |\n"
+           "           write_stmia | write_vst1 | write_vstr | write_vstmia | memset |\n"
+           "           read_ldrd | read_ldmia | read_vld1 | read_vldr | read_vldmia\n"
+           "  multithread_bandwidth [--size BYTES]\n"
+           "    --type copy_ldrd_strd | copy_ldmia_stmia | copy_vld1_vst1 |\n"
+           "           copy_vldr_vstr | copy_vldmia_vstmia | memcpy | write_strd |\n"
+           "           write_stmia | write_vst1 | write_vstr | write_vstmia | memset |\n"
+           "           read_ldrd | read_ldmia | read_vld1 | read_vldr | read_vldmia\n"
+           "    --num_threads NUM_THREADS_TO_RUN\n"
+           "  malloc [fill]\n"
+           "  madvise\n"
+           "  resampler\n"
+           "  stack (stack smasher)\n"
+           "  crawl\n"
+           , p);
+}
+
+int copy_bandwidth(int argc, char** argv);
+int write_bandwidth(int argc, char** argv);
+int read_bandwidth(int argc, char** argv);
+int per_core_bandwidth(int argc, char** argv);
+int multithread_bandwidth(int argc, char** argv);
+int malloc_test(int argc, char** argv);
+int madvise_test(int argc, char** argv);
+int stack_smasher_test(int argc, char** argv);
+int crawl_test(int argc, char** argv);
+int fp_test(int argc, char** argv);
+
+typedef struct {
+    const char *cmd_name;
+    int (*func)(int argc, char** argv);
+} function_t;
+
+function_t function_table[] = {
+    { "malloc", malloc_test },
+    { "madvise", madvise_test },
+    { "stack", stack_smasher_test },
+    { "crawl", crawl_test },
+    { "fp", fp_test },
+    { "copy_bandwidth", copy_bandwidth },
+    { "write_bandwidth", write_bandwidth },
+    { "read_bandwidth", read_bandwidth },
+    { "per_core_bandwidth", per_core_bandwidth },
+    { "multithread_bandwidth", multithread_bandwidth },
+};
+
+int main(int argc, char** argv) {
+    if (argc == 1) {
+        usage(argv[0]);
+        return 0;
+    }
+    int err = -1;
+    for (unsigned int i = 0; i < sizeof(function_table)/sizeof(function_t); i++) {
+        if (strcmp(argv[1], function_table[i].cmd_name) == 0) {
+            err = (*function_table[i].func)(argc-1, argv+1);
+            break;
+        }
+    }
+    if (err) {
+        usage(argv[0]);
+    }
+    return err;
+}
+
+int malloc_test(int argc, char** argv) {
+    bool fill = (argc>=2 && !strcmp(argv[1], "fill"));
+    size_t total = 0;
+    size_t size = 0x40000000;
+    while (size) {
+        void* addr = malloc(size);
+        if (addr == 0) {
+            printf("size = %9zd failed\n", size);
+            size >>= 1;
+        } else {
+            total += size;
+            printf("size = %9zd, addr = %p (total = %9zd (%zd MB))\n",
+                    size, addr, total, total / (1024*1024));
+            if (fill) {
+                printf("filling...\n");
+                fflush(stdout);
+                memset(addr, 0, size);
+            }
+            size = size + (size>>1);
+        }
+    }
+    printf("done. allocated %zd MB\n", total / (1024*1024));
+    return 0;
+}
+
+int madvise_test(int, char**) {
+    for (int i=0 ; i<2 ; i++) {
+        size_t size = i==0 ? 4096 : 48*1024*1024; // 48 MB
+        printf("Allocating %zd MB... ", size/(1024*1024)); fflush(stdout);
+        void* addr1 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+        printf("%p (%s)\n", addr1, addr1==(void*)-1 ? "failed" : "OK"); fflush(stdout);
+
+        printf("touching %p...\n", addr1); fflush(stdout);
+        memset(addr1, 0x55, size);
+
+        printf("advising DONTNEED...\n"); fflush(stdout);
+        madvise(addr1, size, MADV_DONTNEED);
+
+        printf("reading back %p...\n", addr1); fflush(stdout);
+        if (*(long*)addr1 == 0) {
+            printf("madvise freed some pages\n");
+        } else if (*(long*)addr1 == 0x55555555) {
+            printf("pages are still there\n");
+        } else {
+            printf("getting garbage back\n");
+        }
+
+        printf("Allocating %zd MB... ", size/(1024*1024)); fflush(stdout);
+        void* addr2 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+        printf("%p (%s)\n", addr2, addr2==(void*)-1 ? "failed" : "OK"); fflush(stdout);
+
+        printf("touching %p...\n", addr2); fflush(stdout);
+        memset(addr2, 0xAA, size);
+
+        printf("unmap %p ...\n", addr2); fflush(stdout);
+        munmap(addr2, size);
+
+        printf("touching %p...\n", addr1); fflush(stdout);
+        memset(addr1, 0x55, size);
+
+        printf("unmap %p ...\n", addr1); fflush(stdout);
+        munmap(addr1, size);
+    }
+
+    printf("Done\n"); fflush(stdout);
+    return 0;
+}
+
+int stack_smasher_test(int, char**) {
+    int dummy = 0;
+    printf("corrupting our stack...\n");
+    *(volatile long long*)&dummy = 0;
+    return 0;
+}
+
+// --------------------------------------------------------------------
+
+extern "C" void thumb_function_1(int*p);
+extern "C" void thumb_function_2(int*p);
+extern "C" void arm_function_3(int*p);
+extern "C" void arm_function_2(int*p);
+extern "C" void arm_function_1(int*p);
+
+void arm_function_3(int*) {
+    int a = 0;
+    thumb_function_2(&a);
+}
+
+void arm_function_2(int*) {
+    int a = 0;
+    thumb_function_1(&a);
+}
+
+void arm_function_1(int*) {
+    int a = 0;
+    arm_function_2(&a);
+}
+
+int crawl_test(int, char**) {
+    int a = 0;
+    arm_function_1(&a);
+    return 0;
+}
diff --git a/tests/memtest/memtest.h b/tests/memtest/memtest.h
new file mode 100644
index 0000000..afa6f85
--- /dev/null
+++ b/tests/memtest/memtest.h
@@ -0,0 +1,25 @@
+/*
+ * 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 __MEMTEST_H__
+#define __MEMTEST_H__
+
+typedef long long nsecs_t;
+
+// Function prototypes.
+nsecs_t system_time();
+
+#endif // __MEMTEST_H__
diff --git a/tests/memtest/thumb.cpp b/tests/memtest/thumb.cpp
new file mode 100644
index 0000000..9293966
--- /dev/null
+++ b/tests/memtest/thumb.cpp
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <unwind.h>
+
+extern "C" void arm_function_3(int* p);
+extern "C" void thumb_function_1(int* p);
+extern "C" void thumb_function_2(int* p);
+
+extern "C" _Unwind_Reason_Code trace_function(_Unwind_Context* context, void *) {
+    printf("0x%x\n", _Unwind_GetIP(context));
+    fflush(stdout);
+    return _URC_NO_REASON;
+}
+
+void thumb_function_1(int*) {
+    int a = 0;
+    arm_function_3(&a);
+}
+
+void thumb_function_2(int*) {
+    printf("unwinding...\n");
+    _Unwind_Backtrace(trace_function, (void*) "backtrace!");
+}
diff --git a/tests/mmc_tracepoints/README b/tests/mmc_tracepoints/README
new file mode 100644
index 0000000..37aba30
--- /dev/null
+++ b/tests/mmc_tracepoints/README
@@ -0,0 +1,27 @@
+The code in this directory is used to process data from the mmc tracepoints
+in the kernel.  To turn on mmc tracing, do this:
+
+  adb shell echo 1 >/d/tracing/events/mmc/enable
+  adb shell echo 1 >/d/tracing/tracing_on
+
+To get the trace:
+
+  adb pull /d/tracing/trace
+
+To turn it back off, do:
+
+  adb shell echo 0 >/d/tracing/tracing_enabled
+
+The output is in a form of start/stop pairs.  The ops with rw in the name are
+read or write ops, and the ones with erase in the name are the various erase
+opts.
+
+The mmc_trace_reduce script will take the output from the kernel, and convert it
+to a single line per event, which includes the duration of the event.
+
+This can then be fed into other tools for further analysis.
+
+The file mmc_trace_sample_data contains sample mmc trace data from a Nexus 10.
+It includes read, write and discard entries.  The discard entries came from
+invoking fstrim in vold with "vdc fstrim dotrim".
+
diff --git a/tests/mmc_tracepoints/mmc_trace_reduce b/tests/mmc_tracepoints/mmc_trace_reduce
new file mode 100755
index 0000000..ef6683e
--- /dev/null
+++ b/tests/mmc_tracepoints/mmc_trace_reduce
@@ -0,0 +1,152 @@
+#!/bin/bash
+
+# TO DO
+#   This should be re-written in python.
+
+# Complain about dereferencing unset variables
+set -u
+typeset -i STARTTIME ENDTIME DURATION START_SEC START_USEC DUR_SEC DUR_USEC
+
+if [ "$#" -ne 1 ]
+then
+    echo "Usage: mmc_trace_reduce <trace_file>" >&2
+    exit 1
+fi
+
+exec < "$1"
+
+SAVED_START_LINE=""
+
+while read LINE
+do
+    # Skip comment lines
+    if [ -z "${LINE###*}" ]
+    then
+        continue
+    fi
+
+    # Fix up lines with nuisance spaces
+    LINE=${LINE/AsyncTask /AsyncTask-}
+
+    set $LINE
+
+    if [ "${5##*mmc_blk_*_}" = "start:" ]
+    then
+        if [ ! -z "$SAVED_START_LINE" ]
+        then
+            echo "Ignoring consecutive start line" >&2
+            continue
+        fi
+        SAVED_START_LINE="$LINE"
+
+        # Found a start line.  Extract the interesting bits
+        TMP=${4%:}
+        START_SEC="10#${TMP%%.*}"
+        STARTTIME=START_SEC*1000000
+        START_USEC="10#${TMP##*.}"
+        STARTTIME=STARTTIME+START_USEC
+
+        STARTPARMS="$6"
+        STARTCMD=${STARTPARMS%%,addr=*}
+        STARTCMD=${STARTCMD##*cmd=}
+        STARTADDR=${STARTPARMS%%,size=*}
+        STARTADDR=${STARTADDR##*addr=}
+        STARTSIZE=${STARTPARMS##*size=}
+
+    elif [ "${5##*mmc_blk_*_}" = "end:" ]
+    then
+        # Found an end line. Extract the interesting bits,
+        # then make sure it matches with the saved start line,
+        # Finally, do the math and emit a single reduced line
+        TMP=${4%:}
+        ENDTIME="${TMP%%.*}"
+        ENDTIME=ENDTIME*1000000
+        ENDTIME=ENDTIME+10#${TMP##*.}
+
+        ENDPARMS="$6"
+        ENDCMD=${ENDPARMS%%,addr=*}
+        ENDCMD=${ENDCMD##*cmd=}
+        ENDADDR=${ENDPARMS%%,size=*}
+        ENDADDR=${ENDADDR##*addr=}
+        ENDSIZE=${ENDPARMS##*size=}
+
+        if [ "$ENDCMD" != "$STARTCMD" ]
+        then
+            echo "End cmd doesn't match start cmd, ignoring both" >&2
+            SAVED_START_LINE=""
+            continue
+        fi
+        if [ "$ENDADDR" != "$STARTADDR" ]
+        then
+            echo "End addr doesn't match start addr, ignoring both" >&2
+            SAVED_START_LINE=""
+            continue
+        fi
+        if [ "$ENDSIZE" != "$STARTSIZE" ]
+        then
+            echo "End size doesn't match start size, ignoring both" >&2
+            SAVED_START_LINE=""
+            continue
+        fi
+
+        # Turn the command number into a command the flash analysis tool
+        # understands.  The tool doesn't differentiate between the different
+        # forms erase, so just emit "discard" for all of them.  Also, ignore
+        # the secure_trim2 and sanitize commands as the tool doesn't know
+        # about them either.
+        if [ "$ENDCMD" -eq 18 ]
+        then
+            ENDCMD="read"
+        elif [ "$ENDCMD" -eq 25 ]
+        then
+            ENDCMD="write"
+        elif [ "$ENDCMD" -eq 32 ]
+        then
+            ENDCMD="flush"
+            continue
+        elif [ "$ENDCMD" -eq 0 ]
+        then
+            ENDCMD="discard"
+        elif [ "$ENDCMD" -eq 1 ]
+        then
+            ENDCMD="discard"
+        elif [ "$ENDCMD" -eq 3 ]
+        then
+            ENDCMD="discard"
+        elif [ "$ENDCMD" -eq 2147483648 ] # 0x80000000
+        then
+            ENDCMD="discard"
+        elif [ "$ENDCMD" -eq 2147483649 ] # 0x80000001
+        then
+            ENDCMD="discard"
+        elif [ "$ENDCMD" -eq 2147516416 ] # 0x80008000
+        then
+            # Ignore, as the analysis tool doesn't deal with this
+            # ENDCMD="secure_trim2"
+            SAVED_START_LINE=""
+            continue
+        elif [ "$ENDCMD" -eq 165 ]
+        then
+            # Ignore, as the analysis tool doesn't deal with this
+            # ENDCMD="sanitize"
+            SAVED_START_LINE=""
+            continue
+        else
+            echo "Unrecognized command $ENDCMD, ignoring" >&2
+            SAVED_START_LINE=""
+            continue
+        fi
+
+        DURATION=ENDTIME-STARTTIME
+        DUR_SEC=DURATION/1000000
+        DUR_USEC=DURATION%1000000
+
+        printf "$%s,%s,%s,%d.%06d,%d.%06d\n" "$ENDCMD" "$ENDADDR" "$ENDSIZE" "$START_SEC" "$START_USEC" "$DUR_SEC" "$DUR_USEC"
+
+        SAVED_START_LINE=""
+    fi
+
+    # Ignore unknown lines and continue
+
+done
+
diff --git a/tests/mmc_tracepoints/mmc_trace_sample_data b/tests/mmc_tracepoints/mmc_trace_sample_data
new file mode 100644
index 0000000..4e62dcb
--- /dev/null
+++ b/tests/mmc_tracepoints/mmc_trace_sample_data
@@ -0,0 +1,1545 @@
+# tracer: nop
+#
+# entries-in-buffer/entries-written: 1534/1534   #P:2
+#
+#                              _-----=> irqs-off
+#                             / _----=> need-resched
+#                            | / _---=> hardirq/softirq
+#                            || / _--=> preempt-depth
+#                            ||| /     delay
+#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
+#              | |       |   ||||       |         |
+         mmcqd/0-82    [000] ...1    49.828932: mmc_blk_rw_start: cmd=25,addr=0x002c6518,size=0x00000010
+           <...>-1484  [000] ..s4    49.829171: mmc_blk_rw_end: cmd=25,addr=0x002c6518,size=0x00000010
+         mmcqd/0-82    [000] ...1    49.830095: mmc_blk_rw_start: cmd=25,addr=0x002c6528,size=0x00000008
+     kworker/0:2-48    [000] ..s4    49.830218: mmc_blk_rw_end: cmd=25,addr=0x002c6528,size=0x00000008
+         mmcqd/0-82    [000] ...1    52.465957: mmc_blk_rw_start: cmd=18,addr=0x001ad578,size=0x00000020
+          <idle>-0     [000] ..s3    52.466404: mmc_blk_rw_end: cmd=18,addr=0x001ad578,size=0x00000020
+         mmcqd/0-82    [000] ...1    52.492868: mmc_blk_rw_start: cmd=18,addr=0x001aecb8,size=0x00000020
+          <idle>-0     [000] ..s3    52.493157: mmc_blk_rw_end: cmd=18,addr=0x001aecb8,size=0x00000020
+         mmcqd/0-82    [000] ...1    54.834287: mmc_blk_rw_start: cmd=25,addr=0x005420a8,size=0x00000008
+          <idle>-0     [000] ..s3    54.834383: mmc_blk_rw_end: cmd=25,addr=0x005420a8,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.114476: mmc_blk_rw_start: cmd=18,addr=0x0013fb18,size=0x00000020
+          <idle>-0     [000] .Ns3    56.114862: mmc_blk_rw_end: cmd=18,addr=0x0013fb18,size=0x00000020
+         mmcqd/0-82    [000] ...1    56.115150: mmc_blk_rw_start: cmd=18,addr=0x0013fb38,size=0x00000040
+        Binder_4-434   [000] ..s3    56.115539: mmc_blk_rw_end: cmd=18,addr=0x0013fb38,size=0x00000040
+         mmcqd/0-82    [000] ...1    56.115616: mmc_blk_rw_start: cmd=18,addr=0x0013faf0,size=0x00000020
+        Binder_4-434   [000] ..s2    56.115856: mmc_blk_rw_end: cmd=18,addr=0x0013faf0,size=0x00000020
+         mmcqd/0-82    [000] ...1    56.118937: mmc_blk_rw_start: cmd=18,addr=0x0013fb78,size=0x00000200
+          <idle>-0     [000] ..s3    56.120836: mmc_blk_rw_end: cmd=18,addr=0x0013fb78,size=0x00000200
+         mmcqd/0-82    [000] ...1    56.123287: mmc_blk_rw_start: cmd=18,addr=0x0013faa8,size=0x00000020
+          <idle>-0     [000] .Ns3    56.123668: mmc_blk_rw_end: cmd=18,addr=0x0013faa8,size=0x00000020
+         mmcqd/0-82    [000] ...1    56.125172: mmc_blk_rw_start: cmd=18,addr=0x0013fb10,size=0x00000008
+        Compiler-387   [000] ..s4    56.125356: mmc_blk_rw_end: cmd=18,addr=0x0013fb10,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.136772: mmc_blk_rw_start: cmd=18,addr=0x0013fd80,size=0x00000008
+          <idle>-0     [000] ..s3    56.136934: mmc_blk_rw_end: cmd=18,addr=0x0013fd80,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.138223: mmc_blk_rw_start: cmd=18,addr=0x0013fda0,size=0x00000008
+          <idle>-0     [000] ..s3    56.138395: mmc_blk_rw_end: cmd=18,addr=0x0013fda0,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.398796: mmc_blk_rw_start: cmd=18,addr=0x0035af18,size=0x00000020
+   WindowManager-396   [000] ..s2    56.399184: mmc_blk_rw_end: cmd=18,addr=0x0035af18,size=0x00000020
+         mmcqd/0-82    [000] ...1    56.399205: mmc_blk_rw_start: cmd=18,addr=0x0035af40,size=0x000000c0
+   WindowManager-396   [000] ..s2    56.399992: mmc_blk_rw_end: cmd=18,addr=0x0035af40,size=0x000000c0
+         mmcqd/0-82    [000] ...1    56.400029: mmc_blk_rw_start: cmd=18,addr=0x00361000,size=0x00000018
+   WindowManager-396   [000] ..s2    56.400300: mmc_blk_rw_end: cmd=18,addr=0x00361000,size=0x00000018
+         mmcqd/0-82    [000] ...1    56.400358: mmc_blk_rw_start: cmd=18,addr=0x003610e8,size=0x00000088
+   WindowManager-396   [000] ..s2    56.400993: mmc_blk_rw_end: cmd=18,addr=0x003610e8,size=0x00000088
+         mmcqd/0-82    [000] ...1    56.402605: mmc_blk_rw_start: cmd=18,addr=0x0035aab8,size=0x00000100
+   WindowManager-396   [000] .Ns3    56.403653: mmc_blk_rw_end: cmd=18,addr=0x0035aab8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.404001: mmc_blk_rw_start: cmd=18,addr=0x0035a250,size=0x00000100
+   WindowManager-396   [000] ..s3    56.404986: mmc_blk_rw_end: cmd=18,addr=0x0035a250,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.405199: mmc_blk_rw_start: cmd=18,addr=0x0035ade0,size=0x00000100
+   WindowManager-396   [000] ..s3    56.406153: mmc_blk_rw_end: cmd=18,addr=0x0035ade0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.406346: mmc_blk_rw_start: cmd=18,addr=0x0035a020,size=0x000000e8
+   WindowManager-396   [000] ..s2    56.407260: mmc_blk_rw_end: cmd=18,addr=0x0035a020,size=0x000000e8
+         mmcqd/0-82    [000] ...1    56.407510: mmc_blk_rw_start: cmd=18,addr=0x0035a108,size=0x00000090
+        Compiler-387   [000] ..s2    56.408158: mmc_blk_rw_end: cmd=18,addr=0x0035a108,size=0x00000090
+         mmcqd/0-82    [000] ...1    56.408391: mmc_blk_rw_start: cmd=18,addr=0x0035ac10,size=0x00000100
+   WindowManager-396   [000] ..s2    56.409353: mmc_blk_rw_end: cmd=18,addr=0x0035ac10,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.409602: mmc_blk_rw_start: cmd=18,addr=0x0035abb8,size=0x00000058
+   WindowManager-396   [000] ..s2    56.410055: mmc_blk_rw_end: cmd=18,addr=0x0035abb8,size=0x00000058
+         mmcqd/0-82    [000] ...1    56.410338: mmc_blk_rw_start: cmd=18,addr=0x0035ad10,size=0x000000d0
+              UI-395   [000] ..s3    56.411151: mmc_blk_rw_end: cmd=18,addr=0x0035ad10,size=0x000000d0
+         mmcqd/0-82    [000] ...1    56.411364: mmc_blk_rw_start: cmd=18,addr=0x0035a198,size=0x000000b0
+     kworker/0:2-48    [000] ..s2    56.412130: mmc_blk_rw_end: cmd=18,addr=0x0035a198,size=0x000000b0
+         mmcqd/0-82    [000] ...1    56.412521: mmc_blk_rw_start: cmd=18,addr=0x0035a350,size=0x000000b8
+          <idle>-0     [000] ..s3    56.413278: mmc_blk_rw_end: cmd=18,addr=0x0035a350,size=0x000000b8
+         mmcqd/0-82    [000] ...1    56.415655: mmc_blk_rw_start: cmd=18,addr=0x00361018,size=0x000000b8
+          <idle>-0     [000] ..s3    56.416489: mmc_blk_rw_end: cmd=18,addr=0x00361018,size=0x000000b8
+         mmcqd/0-82    [000] ...1    56.416798: mmc_blk_rw_start: cmd=18,addr=0x0035a570,size=0x00000100
+          <idle>-0     [000] ..s3    56.417832: mmc_blk_rw_end: cmd=18,addr=0x0035a570,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.418187: mmc_blk_rw_start: cmd=18,addr=0x0035aa00,size=0x000000b8
+          <idle>-0     [000] ..s3    56.418901: mmc_blk_rw_end: cmd=18,addr=0x0035aa00,size=0x000000b8
+         mmcqd/0-82    [000] ...1    56.422006: mmc_blk_rw_start: cmd=18,addr=0x0035a670,size=0x000000c0
+          <idle>-0     [000] ..s3    56.422804: mmc_blk_rw_end: cmd=18,addr=0x0035a670,size=0x000000c0
+         mmcqd/0-82    [000] ...1    56.424176: mmc_blk_rw_start: cmd=18,addr=0x00b91498,size=0x00000008
+          <idle>-0     [000] ..s3    56.424325: mmc_blk_rw_end: cmd=18,addr=0x00b91498,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.432630: mmc_blk_rw_start: cmd=18,addr=0x0035a918,size=0x000000e8
+          <idle>-0     [000] ..s3    56.433782: mmc_blk_rw_end: cmd=18,addr=0x0035a918,size=0x000000e8
+         mmcqd/0-82    [000] ...1    56.434442: mmc_blk_rw_start: cmd=18,addr=0x0035aee0,size=0x00000038
+          <idle>-0     [000] ..s3    56.434774: mmc_blk_rw_end: cmd=18,addr=0x0035aee0,size=0x00000038
+         mmcqd/0-82    [000] ...1    56.435132: mmc_blk_rw_start: cmd=18,addr=0x0035a248,size=0x00000008
+          <idle>-0     [000] ..s3    56.435292: mmc_blk_rw_end: cmd=18,addr=0x0035a248,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.435774: mmc_blk_rw_start: cmd=18,addr=0x0035a408,size=0x00000100
+          <idle>-0     [000] ..s3    56.436777: mmc_blk_rw_end: cmd=18,addr=0x0035a408,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.436924: mmc_blk_rw_start: cmd=18,addr=0x0035a730,size=0x000000b0
+          <idle>-0     [000] ..s3    56.437682: mmc_blk_rw_end: cmd=18,addr=0x0035a730,size=0x000000b0
+         mmcqd/0-82    [000] ...1    56.443462: mmc_blk_rw_start: cmd=18,addr=0x0035a508,size=0x00000068
+          <idle>-0     [000] ..s3    56.443997: mmc_blk_rw_end: cmd=18,addr=0x0035a508,size=0x00000068
+         mmcqd/0-82    [000] ...1    56.446861: mmc_blk_rw_start: cmd=18,addr=0x003610d0,size=0x00000018
+  ion_chunk_heap-18    [000] ..s2    56.447095: mmc_blk_rw_end: cmd=18,addr=0x003610d0,size=0x00000018
+         mmcqd/0-82    [000] ...1    56.457912: mmc_blk_rw_start: cmd=18,addr=0x0013ffd0,size=0x00000020
+          <idle>-0     [000] ..s3    56.458311: mmc_blk_rw_end: cmd=18,addr=0x0013ffd0,size=0x00000020
+         mmcqd/0-82    [000] ...1    56.503358: mmc_blk_rw_start: cmd=18,addr=0x0013fdb8,size=0x00000008
+          <idle>-0     [000] ..s3    56.503531: mmc_blk_rw_end: cmd=18,addr=0x0013fdb8,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.599614: mmc_blk_rw_start: cmd=18,addr=0x001cae08,size=0x00000020
+           <...>-1488  [000] ..s2    56.599978: mmc_blk_rw_end: cmd=18,addr=0x001cae08,size=0x00000020
+         mmcqd/0-82    [000] ...1    56.600278: mmc_blk_rw_start: cmd=18,addr=0x001dab70,size=0x00000088
+           <...>-1488  [000] .Ns2    56.600968: mmc_blk_rw_end: cmd=18,addr=0x001dab70,size=0x00000088
+         mmcqd/0-82    [000] ...1    56.601458: mmc_blk_rw_start: cmd=18,addr=0x001da970,size=0x00000100
+           <...>-186   [000] ..s4    56.602466: mmc_blk_rw_end: cmd=18,addr=0x001da970,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.602892: mmc_blk_rw_start: cmd=18,addr=0x001cae28,size=0x000000e0
+           <...>-1488  [000] ..s2    56.603805: mmc_blk_rw_end: cmd=18,addr=0x001cae28,size=0x000000e0
+         mmcqd/0-82    [000] ...1    56.604302: mmc_blk_rw_start: cmd=18,addr=0x001f1980,size=0x00000010
+           <...>-1488  [000] ..s2    56.604534: mmc_blk_rw_end: cmd=18,addr=0x001f1980,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.605940: mmc_blk_rw_start: cmd=18,addr=0x001c7f48,size=0x00000018
+           <...>-1488  [000] ..s2    56.606185: mmc_blk_rw_end: cmd=18,addr=0x001c7f48,size=0x00000018
+         mmcqd/0-82    [000] ...1    56.606682: mmc_blk_rw_start: cmd=18,addr=0x00207318,size=0x00000020
+           <...>-1488  [000] ..s2    56.607019: mmc_blk_rw_end: cmd=18,addr=0x00207318,size=0x00000020
+         mmcqd/0-82    [000] ...1    56.607347: mmc_blk_rw_start: cmd=18,addr=0x002073d8,size=0x00000088
+           <...>-1488  [000] ..s2    56.607987: mmc_blk_rw_end: cmd=18,addr=0x002073d8,size=0x00000088
+         mmcqd/0-82    [000] ...1    56.608403: mmc_blk_rw_start: cmd=18,addr=0x00207338,size=0x000000a0
+           <...>-1488  [000] ..s2    56.609126: mmc_blk_rw_end: cmd=18,addr=0x00207338,size=0x000000a0
+         mmcqd/0-82    [000] ...1    56.612141: mmc_blk_rw_start: cmd=18,addr=0x001cbcb0,size=0x00000100
+           <...>-1488  [000] ..s2    56.613209: mmc_blk_rw_end: cmd=18,addr=0x001cbcb0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.615745: mmc_blk_rw_start: cmd=18,addr=0x001caf08,size=0x00000100
+  SurfaceFlinger-150   [000] ..s2    56.616755: mmc_blk_rw_end: cmd=18,addr=0x001caf08,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.616885: mmc_blk_rw_start: cmd=18,addr=0x001d9ff0,size=0x00000100
+        Binder_7-622   [000] ..s4    56.618039: mmc_blk_rw_end: cmd=18,addr=0x001d9ff0,size=0x00000100
+         mmcqd/0-82    [001] ...1    56.619426: mmc_blk_rw_start: cmd=18,addr=0x001da0f0,size=0x00000100
+        Binder_7-622   [000] ..s2    56.620534: mmc_blk_rw_end: cmd=18,addr=0x001da0f0,size=0x00000100
+         mmcqd/0-82    [001] ...1    56.620701: mmc_blk_rw_start: cmd=18,addr=0x001da1f0,size=0x00000100
+          <idle>-0     [000] ..s3    56.621724: mmc_blk_rw_end: cmd=18,addr=0x001da1f0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.621879: mmc_blk_rw_start: cmd=18,addr=0x001cb008,size=0x00000100
+        Binder_B-670   [000] ..s2    56.622887: mmc_blk_rw_end: cmd=18,addr=0x001cb008,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.627277: mmc_blk_rw_start: cmd=18,addr=0x001da2f0,size=0x00000100
+           <...>-1503  [000] ..s2    56.628332: mmc_blk_rw_end: cmd=18,addr=0x001da2f0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.628525: mmc_blk_rw_start: cmd=18,addr=0x001cb108,size=0x00000100
+           <...>-1488  [000] ..s2    56.629524: mmc_blk_rw_end: cmd=18,addr=0x001cb108,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.629924: mmc_blk_rw_start: cmd=18,addr=0x001da3f0,size=0x00000100
+           <...>-1503  [000] ..s2    56.630942: mmc_blk_rw_end: cmd=18,addr=0x001da3f0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.631074: mmc_blk_rw_start: cmd=18,addr=0x001cb208,size=0x00000100
+  SurfaceFlinger-150   [000] ..s2    56.632066: mmc_blk_rw_end: cmd=18,addr=0x001cb208,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.639698: mmc_blk_rw_start: cmd=18,addr=0x001cb308,size=0x00000100
+           <...>-1488  [000] ..s4    56.640734: mmc_blk_rw_end: cmd=18,addr=0x001cb308,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.640888: mmc_blk_rw_start: cmd=18,addr=0x001cb408,size=0x00000100
+           <...>-1488  [000] ..s2    56.641892: mmc_blk_rw_end: cmd=18,addr=0x001cb408,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.641926: mmc_blk_rw_start: cmd=18,addr=0x001da4f0,size=0x00000100
+           <...>-1488  [000] ..s2    56.642952: mmc_blk_rw_end: cmd=18,addr=0x001da4f0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.642981: mmc_blk_rw_start: cmd=18,addr=0x001da5f0,size=0x00000100
+           <...>-1503  [000] ..s2    56.643995: mmc_blk_rw_end: cmd=18,addr=0x001da5f0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.644277: mmc_blk_rw_start: cmd=18,addr=0x001cb508,size=0x00000100
+     kworker/0:1-23    [000] ..s2    56.645266: mmc_blk_rw_end: cmd=18,addr=0x001cb508,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.645946: mmc_blk_rw_start: cmd=18,addr=0x001cb608,size=0x00000100
+          <idle>-0     [000] ..s3    56.646933: mmc_blk_rw_end: cmd=18,addr=0x001cb608,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.647065: mmc_blk_rw_start: cmd=18,addr=0x001da6f0,size=0x00000100
+          <idle>-0     [000] .Ns3    56.648106: mmc_blk_rw_end: cmd=18,addr=0x001da6f0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.651473: mmc_blk_rw_start: cmd=18,addr=0x001cb708,size=0x00000100
+          <idle>-0     [000] ..s3    56.652503: mmc_blk_rw_end: cmd=18,addr=0x001cb708,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.652660: mmc_blk_rw_start: cmd=18,addr=0x001cb808,size=0x00000100
+          <idle>-0     [000] ..s3    56.653650: mmc_blk_rw_end: cmd=18,addr=0x001cb808,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.654708: mmc_blk_rw_start: cmd=18,addr=0x001da7f0,size=0x00000100
+          <idle>-0     [000] ..s3    56.655755: mmc_blk_rw_end: cmd=18,addr=0x001da7f0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.655961: mmc_blk_rw_start: cmd=18,addr=0x001da8f0,size=0x00000080
+           <...>-1488  [000] ..s2    56.656559: mmc_blk_rw_end: cmd=18,addr=0x001da8f0,size=0x00000080
+         mmcqd/0-82    [000] ...1    56.656590: mmc_blk_rw_start: cmd=18,addr=0x001cb908,size=0x00000100
+           <...>-1488  [000] ..s3    56.657590: mmc_blk_rw_end: cmd=18,addr=0x001cb908,size=0x00000100
+         mmcqd/0-82    [001] ...1    56.661710: mmc_blk_rw_start: cmd=18,addr=0x001cba08,size=0x00000100
+           <...>-1488  [000] ..s2    56.662732: mmc_blk_rw_end: cmd=18,addr=0x001cba08,size=0x00000100
+         mmcqd/0-82    [001] ...1    56.663283: mmc_blk_rw_start: cmd=18,addr=0x001cbb08,size=0x00000100
+           <...>-1488  [000] ..s2    56.664267: mmc_blk_rw_end: cmd=18,addr=0x001cbb08,size=0x00000100
+         mmcqd/0-82    [001] ...1    56.664292: mmc_blk_rw_start: cmd=18,addr=0x001daa70,size=0x00000080
+           <...>-204   [000] ..s3    56.664948: mmc_blk_rw_end: cmd=18,addr=0x001daa70,size=0x00000080
+         mmcqd/0-82    [001] ...1    56.664969: mmc_blk_rw_start: cmd=18,addr=0x001cbc08,size=0x000000a8
+  SurfaceFlinger-150   [000] ..s2    56.665694: mmc_blk_rw_end: cmd=18,addr=0x001cbc08,size=0x000000a8
+         mmcqd/0-82    [001] ...1    56.665785: mmc_blk_rw_start: cmd=18,addr=0x001daaf0,size=0x00000080
+  SurfaceFlinger-150   [000] ..s3    56.666372: mmc_blk_rw_end: cmd=18,addr=0x001daaf0,size=0x00000080
+         mmcqd/0-82    [001] ...1    56.697351: mmc_blk_rw_start: cmd=18,addr=0x0013ffa0,size=0x00000008
+           <...>-1503  [000] ..s2    56.697583: mmc_blk_rw_end: cmd=18,addr=0x0013ffa0,size=0x00000008
+         mmcqd/0-82    [001] ...1    56.703729: mmc_blk_rw_start: cmd=18,addr=0x001cbdb0,size=0x000000d0
+   WindowManager-396   [000] ..s2    56.704708: mmc_blk_rw_end: cmd=18,addr=0x001cbdb0,size=0x000000d0
+         mmcqd/0-82    [001] ...1    56.707676: mmc_blk_rw_start: cmd=18,addr=0x001cc148,size=0x00000100
+          <idle>-0     [000] ..s3    56.708698: mmc_blk_rw_end: cmd=18,addr=0x001cc148,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.709038: mmc_blk_rw_start: cmd=18,addr=0x001d35d0,size=0x00000100
+  ion_chunk_heap-18    [000] ..s2    56.710085: mmc_blk_rw_end: cmd=18,addr=0x001d35d0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.710400: mmc_blk_rw_start: cmd=18,addr=0x001d4f18,size=0x00000010
+  ion_chunk_heap-18    [000] ..s3    56.710646: mmc_blk_rw_end: cmd=18,addr=0x001d4f18,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.710661: mmc_blk_rw_start: cmd=18,addr=0x001d4f28,size=0x00000038
+  ion_chunk_heap-18    [000] ..s2    56.711007: mmc_blk_rw_end: cmd=18,addr=0x001d4f28,size=0x00000038
+         mmcqd/0-82    [000] ...1    56.711022: mmc_blk_rw_start: cmd=18,addr=0x001d4f60,size=0x00000010
+  ion_chunk_heap-18    [000] ..s3    56.711188: mmc_blk_rw_end: cmd=18,addr=0x001d4f60,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.711202: mmc_blk_rw_start: cmd=18,addr=0x001d4f70,size=0x00000010
+  ion_chunk_heap-18    [000] ..s4    56.711365: mmc_blk_rw_end: cmd=18,addr=0x001d4f70,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.711385: mmc_blk_rw_start: cmd=18,addr=0x001d4f80,size=0x00000010
+  ion_chunk_heap-18    [000] ..s4    56.711571: mmc_blk_rw_end: cmd=18,addr=0x001d4f80,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.711588: mmc_blk_rw_start: cmd=18,addr=0x001d4f90,size=0x00000010
+  ion_chunk_heap-18    [000] ..s2    56.711769: mmc_blk_rw_end: cmd=18,addr=0x001d4f90,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.711785: mmc_blk_rw_start: cmd=18,addr=0x001d4fa0,size=0x00000010
+           <...>-1523  [000] ..s2    56.711965: mmc_blk_rw_end: cmd=18,addr=0x001d4fa0,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.712020: mmc_blk_rw_start: cmd=18,addr=0x001d4fb0,size=0x00000010
+  ion_chunk_heap-18    [000] ..s2    56.712220: mmc_blk_rw_end: cmd=18,addr=0x001d4fb0,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.712236: mmc_blk_rw_start: cmd=18,addr=0x001d4fc0,size=0x00000010
+  ion_chunk_heap-18    [000] ..s2    56.712423: mmc_blk_rw_end: cmd=18,addr=0x001d4fc0,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.712439: mmc_blk_rw_start: cmd=18,addr=0x001d4fd0,size=0x00000010
+  ion_chunk_heap-18    [000] ..s3    56.712617: mmc_blk_rw_end: cmd=18,addr=0x001d4fd0,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.712633: mmc_blk_rw_start: cmd=18,addr=0x001d4fe0,size=0x00000010
+  ion_chunk_heap-18    [000] ..s3    56.712812: mmc_blk_rw_end: cmd=18,addr=0x001d4fe0,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.712833: mmc_blk_rw_start: cmd=18,addr=0x001d4ff0,size=0x00000020
+  ion_chunk_heap-18    [000] ..s2    56.713092: mmc_blk_rw_end: cmd=18,addr=0x001d4ff0,size=0x00000020
+         mmcqd/0-82    [000] ...1    56.713105: mmc_blk_rw_start: cmd=18,addr=0x001d5010,size=0x00000008
+  ion_chunk_heap-18    [000] ..s2    56.713221: mmc_blk_rw_end: cmd=18,addr=0x001d5010,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.713234: mmc_blk_rw_start: cmd=18,addr=0x001cdc68,size=0x00000100
+  ion_chunk_heap-18    [000] ..s2    56.714260: mmc_blk_rw_end: cmd=18,addr=0x001cdc68,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.714479: mmc_blk_rw_start: cmd=18,addr=0x001cc248,size=0x00000088
+           <...>-95    [000] ..s3    56.715077: mmc_blk_rw_end: cmd=18,addr=0x001cc248,size=0x00000088
+         mmcqd/0-82    [000] ...1    56.716732: mmc_blk_rw_start: cmd=18,addr=0x0013fe68,size=0x00000008
+  ion_chunk_heap-18    [000] ..s3    56.717001: mmc_blk_rw_end: cmd=18,addr=0x0013fe68,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.717019: mmc_blk_rw_start: cmd=18,addr=0x001b9410,size=0x00000018
+  ion_chunk_heap-18    [000] ..s3    56.717306: mmc_blk_rw_end: cmd=18,addr=0x001b9410,size=0x00000018
+         mmcqd/0-82    [000] ...1    56.717328: mmc_blk_rw_start: cmd=18,addr=0x001cd4f0,size=0x00000100
+        Binder_1-198   [000] ..s2    56.718333: mmc_blk_rw_end: cmd=18,addr=0x001cd4f0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.719547: mmc_blk_rw_start: cmd=18,addr=0x001cd710,size=0x00000100
+  ion_chunk_heap-18    [000] ..s2    56.720525: mmc_blk_rw_end: cmd=18,addr=0x001cd710,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.720781: mmc_blk_rw_start: cmd=18,addr=0x001cd970,size=0x00000100
+  ion_chunk_heap-18    [000] ..s3    56.721794: mmc_blk_rw_end: cmd=18,addr=0x001cd970,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.722013: mmc_blk_rw_start: cmd=18,addr=0x001cf240,size=0x00000100
+           <...>-204   [000] ..s3    56.722961: mmc_blk_rw_end: cmd=18,addr=0x001cf240,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.723195: mmc_blk_rw_start: cmd=18,addr=0x001d12b8,size=0x00000100
+  ion_chunk_heap-18    [000] ..s3    56.724218: mmc_blk_rw_end: cmd=18,addr=0x001d12b8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.724309: mmc_blk_rw_start: cmd=18,addr=0x0013fda8,size=0x00000010
+  ion_chunk_heap-18    [000] ..s2    56.724519: mmc_blk_rw_end: cmd=18,addr=0x0013fda8,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.724532: mmc_blk_rw_start: cmd=18,addr=0x0013fdc0,size=0x00000048
+  ion_chunk_heap-18    [000] ..s2    56.724938: mmc_blk_rw_end: cmd=18,addr=0x0013fdc0,size=0x00000048
+         mmcqd/0-82    [000] ...1    56.726292: mmc_blk_rw_start: cmd=18,addr=0x0013ff90,size=0x00000008
+          <idle>-0     [000] ..s3    56.726465: mmc_blk_rw_end: cmd=18,addr=0x0013ff90,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.728492: mmc_blk_rw_start: cmd=18,addr=0x0013ff30,size=0x00000008
+          <idle>-0     [000] ..s3    56.728670: mmc_blk_rw_end: cmd=18,addr=0x0013ff30,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.729188: mmc_blk_rw_start: cmd=18,addr=0x0013ff38,size=0x00000058
+          <idle>-0     [000] ..s3    56.729717: mmc_blk_rw_end: cmd=18,addr=0x0013ff38,size=0x00000058
+         mmcqd/0-82    [000] ...1    56.729769: mmc_blk_rw_start: cmd=18,addr=0x0013ff98,size=0x00000008
+          <idle>-0     [000] ..s3    56.729932: mmc_blk_rw_end: cmd=18,addr=0x0013ff98,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.729978: mmc_blk_rw_start: cmd=18,addr=0x0013ffa8,size=0x00000010
+          <idle>-0     [000] ..s3    56.730221: mmc_blk_rw_end: cmd=18,addr=0x0013ffa8,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.730269: mmc_blk_rw_start: cmd=18,addr=0x0013feb8,size=0x00000078
+          <idle>-0     [000] ..s3    56.730903: mmc_blk_rw_end: cmd=18,addr=0x0013feb8,size=0x00000078
+         mmcqd/0-82    [000] ...1    56.733814: mmc_blk_rw_start: cmd=18,addr=0x0013fe78,size=0x00000020
+          <idle>-0     [000] ..s3    56.734174: mmc_blk_rw_end: cmd=18,addr=0x0013fe78,size=0x00000020
+         mmcqd/0-82    [000] ...1    56.736291: mmc_blk_rw_start: cmd=18,addr=0x0013fd88,size=0x00000018
+          <idle>-0     [000] ..s3    56.736551: mmc_blk_rw_end: cmd=18,addr=0x0013fd88,size=0x00000018
+         mmcqd/0-82    [000] ...1    56.736604: mmc_blk_rw_start: cmd=18,addr=0x0013fd78,size=0x00000008
+           <...>-1488  [000] ..s2    56.736753: mmc_blk_rw_end: cmd=18,addr=0x0013fd78,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.739250: mmc_blk_rw_start: cmd=18,addr=0x001d8ec0,size=0x00000100
+           <...>-406   [000] .Ns2    56.740339: mmc_blk_rw_end: cmd=18,addr=0x001d8ec0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.740691: mmc_blk_rw_start: cmd=18,addr=0x001d1738,size=0x00000100
+          <idle>-0     [000] ..s3    56.741682: mmc_blk_rw_end: cmd=18,addr=0x001d1738,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.741965: mmc_blk_rw_start: cmd=18,addr=0x001d1b90,size=0x00000100
+          <idle>-0     [000] ..s3    56.742953: mmc_blk_rw_end: cmd=18,addr=0x001d1b90,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.743297: mmc_blk_rw_start: cmd=18,addr=0x001d2a98,size=0x00000100
+           <...>-1496  [000] ..s2    56.744359: mmc_blk_rw_end: cmd=18,addr=0x001d2a98,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.744585: mmc_blk_rw_start: cmd=18,addr=0x001d3478,size=0x00000100
+          <idle>-0     [000] ..s3    56.745592: mmc_blk_rw_end: cmd=18,addr=0x001d3478,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.745846: mmc_blk_rw_start: cmd=18,addr=0x001d3b30,size=0x00000100
+          <idle>-0     [000] ..s3    56.746829: mmc_blk_rw_end: cmd=18,addr=0x001d3b30,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.747117: mmc_blk_rw_start: cmd=18,addr=0x001d9ba8,size=0x00000100
+          <idle>-0     [000] ..s3    56.748190: mmc_blk_rw_end: cmd=18,addr=0x001d9ba8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.748465: mmc_blk_rw_start: cmd=18,addr=0x001d2df0,size=0x00000100
+          <idle>-0     [000] ..s3    56.749470: mmc_blk_rw_end: cmd=18,addr=0x001d2df0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.749865: mmc_blk_rw_start: cmd=18,addr=0x001ce280,size=0x00000100
+  SurfaceFlinger-150   [000] ..s4    56.750866: mmc_blk_rw_end: cmd=18,addr=0x001ce280,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.751289: mmc_blk_rw_start: cmd=18,addr=0x001d3578,size=0x00000058
+          <idle>-0     [000] ..s3    56.751761: mmc_blk_rw_end: cmd=18,addr=0x001d3578,size=0x00000058
+         mmcqd/0-82    [000] ...1    56.751845: mmc_blk_rw_start: cmd=18,addr=0x001d58c8,size=0x00000100
+          <idle>-0     [000] ..s3    56.752893: mmc_blk_rw_end: cmd=18,addr=0x001d58c8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.754212: mmc_blk_rw_start: cmd=18,addr=0x0013fe70,size=0x00000008
+          <idle>-0     [000] ..s3    56.754450: mmc_blk_rw_end: cmd=18,addr=0x0013fe70,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.754496: mmc_blk_rw_start: cmd=18,addr=0x0013fe98,size=0x00000020
+           <...>-1497  [000] ..s2    56.754842: mmc_blk_rw_end: cmd=18,addr=0x0013fe98,size=0x00000020
+         mmcqd/0-82    [000] ...1    56.754860: mmc_blk_rw_start: cmd=18,addr=0x001d0740,size=0x00000100
+           <...>-1488  [000] ..s3    56.755885: mmc_blk_rw_end: cmd=18,addr=0x001d0740,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.759274: mmc_blk_rw_start: cmd=18,addr=0x001d5028,size=0x00000100
+           <...>-1488  [000] .Ns4    56.760368: mmc_blk_rw_end: cmd=18,addr=0x001d5028,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.764203: mmc_blk_rw_start: cmd=18,addr=0x001cce38,size=0x00000100
+           <...>-95    [000] ..s3    56.765272: mmc_blk_rw_end: cmd=18,addr=0x001cce38,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.765725: mmc_blk_rw_start: cmd=18,addr=0x001d0650,size=0x000000f0
+           <...>-1488  [000] ..s2    56.766713: mmc_blk_rw_end: cmd=18,addr=0x001d0650,size=0x000000f0
+         mmcqd/0-82    [001] ...1    56.767749: mmc_blk_rw_start: cmd=18,addr=0x001d3d60,size=0x00000070
+           <...>-1488  [000] ..s2    56.768374: mmc_blk_rw_end: cmd=18,addr=0x001d3d60,size=0x00000070
+         mmcqd/0-82    [001] ...1    56.769290: mmc_blk_rw_start: cmd=18,addr=0x001d3dd0,size=0x00000090
+           <...>-1488  [000] ..s2    56.769942: mmc_blk_rw_end: cmd=18,addr=0x001d3dd0,size=0x00000090
+         mmcqd/0-82    [001] ...1    56.774342: mmc_blk_rw_start: cmd=18,addr=0x001cd8d0,size=0x000000a0
+           <...>-406   [000] ..s4    56.775119: mmc_blk_rw_end: cmd=18,addr=0x001cd8d0,size=0x000000a0
+         mmcqd/0-82    [001] ...1    56.775689: mmc_blk_rw_start: cmd=18,addr=0x001d6330,size=0x00000100
+        Compiler-1495  [000] ..s2    56.776705: mmc_blk_rw_end: cmd=18,addr=0x001d6330,size=0x00000100
+         mmcqd/0-82    [001] ...1    56.777034: mmc_blk_rw_start: cmd=18,addr=0x001d36d0,size=0x00000080
+        Compiler-1495  [000] ..s2    56.777586: mmc_blk_rw_end: cmd=18,addr=0x001d36d0,size=0x00000080
+         mmcqd/0-82    [001] ...1    56.777901: mmc_blk_rw_start: cmd=18,addr=0x001d92d0,size=0x00000100
+        Compiler-1495  [000] ..s2    56.778879: mmc_blk_rw_end: cmd=18,addr=0x001d92d0,size=0x00000100
+         mmcqd/0-82    [001] ...1    56.779219: mmc_blk_rw_start: cmd=18,addr=0x001d5838,size=0x00000090
+        Compiler-1495  [000] ..s2    56.779826: mmc_blk_rw_end: cmd=18,addr=0x001d5838,size=0x00000090
+         mmcqd/0-82    [001] ...1    56.780091: mmc_blk_rw_start: cmd=18,addr=0x001cbe80,size=0x00000100
+           <...>-1488  [000] ..s2    56.781135: mmc_blk_rw_end: cmd=18,addr=0x001cbe80,size=0x00000100
+         mmcqd/0-82    [001] ...1    56.781221: mmc_blk_rw_start: cmd=18,addr=0x001d5128,size=0x00000080
+           <...>-1488  [000] ..s2    56.781804: mmc_blk_rw_end: cmd=18,addr=0x001d5128,size=0x00000080
+         mmcqd/0-82    [001] ...1    56.782053: mmc_blk_rw_start: cmd=18,addr=0x001d91c0,size=0x00000100
+           <...>-1488  [000] ..s2    56.783031: mmc_blk_rw_end: cmd=18,addr=0x001d91c0,size=0x00000100
+         mmcqd/0-82    [001] ...1    56.784197: mmc_blk_rw_start: cmd=18,addr=0x001d51a8,size=0x00000100
+          <idle>-0     [000] ..s3    56.785337: mmc_blk_rw_end: cmd=18,addr=0x001d51a8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.785476: mmc_blk_rw_start: cmd=18,addr=0x001d5018,size=0x00000010
+          <idle>-0     [000] ..s3    56.785673: mmc_blk_rw_end: cmd=18,addr=0x001d5018,size=0x00000010
+         mmcqd/0-82    [000] ...1    56.786668: mmc_blk_rw_start: cmd=18,addr=0x001d1ab0,size=0x000000e0
+          <idle>-0     [000] ..s3    56.787689: mmc_blk_rw_end: cmd=18,addr=0x001d1ab0,size=0x000000e0
+         mmcqd/0-82    [000] ...1    56.788047: mmc_blk_rw_start: cmd=18,addr=0x001d93d0,size=0x00000098
+          <idle>-0     [000] ..s3    56.788712: mmc_blk_rw_end: cmd=18,addr=0x001d93d0,size=0x00000098
+         mmcqd/0-82    [000] ...1    56.789370: mmc_blk_rw_start: cmd=18,addr=0x001d55c8,size=0x00000100
+          <idle>-0     [000] ..s3    56.790423: mmc_blk_rw_end: cmd=18,addr=0x001d55c8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.790915: mmc_blk_rw_start: cmd=18,addr=0x001d9578,size=0x00000100
+          <idle>-0     [000] ..s3    56.791962: mmc_blk_rw_end: cmd=18,addr=0x001d9578,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.792834: mmc_blk_rw_start: cmd=18,addr=0x001d56c8,size=0x000000d0
+          <idle>-0     [000] ..s3    56.793714: mmc_blk_rw_end: cmd=18,addr=0x001d56c8,size=0x000000d0
+         mmcqd/0-82    [000] ...1    56.793982: mmc_blk_rw_start: cmd=18,addr=0x001ce0a0,size=0x00000100
+          <idle>-0     [000] ..s3    56.794987: mmc_blk_rw_end: cmd=18,addr=0x001ce0a0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.795529: mmc_blk_rw_start: cmd=18,addr=0x001ce950,size=0x00000100
+          <idle>-0     [000] ..s3    56.796486: mmc_blk_rw_end: cmd=18,addr=0x001ce950,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.796968: mmc_blk_rw_start: cmd=18,addr=0x001d54a8,size=0x00000100
+          <idle>-0     [000] ..s3    56.798042: mmc_blk_rw_end: cmd=18,addr=0x001d54a8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.799026: mmc_blk_rw_start: cmd=18,addr=0x001d10c8,size=0x00000100
+           <...>-1488  [000] ..s2    56.800076: mmc_blk_rw_end: cmd=18,addr=0x001d10c8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.800814: mmc_blk_rw_start: cmd=18,addr=0x001cdf48,size=0x00000100
+           <...>-1488  [000] ..s2    56.801860: mmc_blk_rw_end: cmd=18,addr=0x001cdf48,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.807747: mmc_blk_rw_start: cmd=18,addr=0x001cc628,size=0x00000100
+          <idle>-0     [000] ..s3    56.808883: mmc_blk_rw_end: cmd=18,addr=0x001cc628,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.810313: mmc_blk_rw_start: cmd=18,addr=0x001cc728,size=0x00000100
+          <idle>-0     [000] ..s3    56.811414: mmc_blk_rw_end: cmd=18,addr=0x001cc728,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.838043: mmc_blk_rw_start: cmd=18,addr=0x001d52a8,size=0x00000098
+           <...>-1509  [000] ..s2    56.838880: mmc_blk_rw_end: cmd=18,addr=0x001d52a8,size=0x00000098
+         mmcqd/0-82    [000] ...1    56.839823: mmc_blk_rw_start: cmd=18,addr=0x001cee08,size=0x00000100
+          <idle>-0     [000] ..s3    56.840907: mmc_blk_rw_end: cmd=18,addr=0x001cee08,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.841309: mmc_blk_rw_start: cmd=18,addr=0x001cc980,size=0x00000100
+          <idle>-0     [000] ..s3    56.842316: mmc_blk_rw_end: cmd=18,addr=0x001cc980,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.842635: mmc_blk_rw_start: cmd=18,addr=0x001d6430,size=0x00000100
+          <idle>-0     [000] ..s3    56.843647: mmc_blk_rw_end: cmd=18,addr=0x001d6430,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.843694: mmc_blk_rw_start: cmd=18,addr=0x001d5420,size=0x00000088
+          <idle>-0     [000] ..s3    56.844291: mmc_blk_rw_end: cmd=18,addr=0x001d5420,size=0x00000088
+         mmcqd/0-82    [000] ...1    56.844588: mmc_blk_rw_start: cmd=18,addr=0x001d3750,size=0x00000100
+          <idle>-0     [000] ..s3    56.845580: mmc_blk_rw_end: cmd=18,addr=0x001d3750,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.845630: mmc_blk_rw_start: cmd=18,addr=0x001d15d0,size=0x00000100
+          <idle>-0     [000] ..s3    56.846655: mmc_blk_rw_end: cmd=18,addr=0x001d15d0,size=0x00000100
+         mmcqd/0-82    [001] ...1    56.847372: mmc_blk_rw_start: cmd=18,addr=0x001cf120,size=0x00000100
+          <idle>-0     [000] ..s3    56.848387: mmc_blk_rw_end: cmd=18,addr=0x001cf120,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.848652: mmc_blk_rw_start: cmd=18,addr=0x001cc498,size=0x00000100
+              UI-395   [000] ..s2    56.849701: mmc_blk_rw_end: cmd=18,addr=0x001cc498,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.853069: mmc_blk_rw_start: cmd=18,addr=0x001cef08,size=0x000000b0
+          <idle>-0     [000] ..s3    56.853834: mmc_blk_rw_end: cmd=18,addr=0x001cef08,size=0x000000b0
+         mmcqd/0-82    [000] ...1    56.854772: mmc_blk_rw_start: cmd=18,addr=0x001cf340,size=0x000000b0
+          <idle>-0     [000] ..s3    56.855503: mmc_blk_rw_end: cmd=18,addr=0x001cf340,size=0x000000b0
+         mmcqd/0-82    [000] ...1    56.855902: mmc_blk_rw_start: cmd=18,addr=0x001cf560,size=0x00000100
+          <idle>-0     [000] ..s3    56.856920: mmc_blk_rw_end: cmd=18,addr=0x001cf560,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.857426: mmc_blk_rw_start: cmd=18,addr=0x001d5340,size=0x000000b8
+          <idle>-0     [000] ..s3    56.858165: mmc_blk_rw_end: cmd=18,addr=0x001d5340,size=0x000000b8
+         mmcqd/0-82    [000] ...1    56.858818: mmc_blk_rw_start: cmd=18,addr=0x001cf3f0,size=0x000000b8
+     kworker/0:1-23    [000] ..s2    56.859605: mmc_blk_rw_end: cmd=18,addr=0x001cf3f0,size=0x000000b8
+         mmcqd/0-82    [000] ...1    56.864629: mmc_blk_rw_start: cmd=18,addr=0x001d3908,size=0x00000100
+           <...>-95    [000] ..s3    56.865633: mmc_blk_rw_end: cmd=18,addr=0x001d3908,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.866118: mmc_blk_rw_start: cmd=18,addr=0x001cc3f0,size=0x000000a8
+        Binder_2-130   [000] ..s2    56.866844: mmc_blk_rw_end: cmd=18,addr=0x001cc3f0,size=0x000000a8
+         mmcqd/0-82    [000] ...1    56.868586: mmc_blk_rw_start: cmd=18,addr=0x001d3aa8,size=0x00000088
+          <idle>-0     [000] ..s3    56.869318: mmc_blk_rw_end: cmd=18,addr=0x001d3aa8,size=0x00000088
+         mmcqd/0-82    [000] ...1    56.869655: mmc_blk_rw_start: cmd=18,addr=0x001ccf38,size=0x000000d0
+          <idle>-0     [000] ..s3    56.870499: mmc_blk_rw_end: cmd=18,addr=0x001ccf38,size=0x000000d0
+         mmcqd/0-82    [000] ...1    56.870776: mmc_blk_rw_start: cmd=18,addr=0x001cea50,size=0x00000080
+          <idle>-0     [000] ..s3    56.871323: mmc_blk_rw_end: cmd=18,addr=0x001cea50,size=0x00000080
+         mmcqd/0-82    [000] ...1    56.871650: mmc_blk_rw_start: cmd=18,addr=0x001cc2d0,size=0x00000100
+          <idle>-0     [000] ..s3    56.872658: mmc_blk_rw_end: cmd=18,addr=0x001cc2d0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.872765: mmc_blk_rw_start: cmd=18,addr=0x001d3850,size=0x000000b8
+          <idle>-0     [000] ..s3    56.873509: mmc_blk_rw_end: cmd=18,addr=0x001d3850,size=0x000000b8
+         mmcqd/0-82    [000] ...1    56.874190: mmc_blk_rw_start: cmd=18,addr=0x001d3a08,size=0x00000088
+          <idle>-0     [000] ..s3    56.874798: mmc_blk_rw_end: cmd=18,addr=0x001d3a08,size=0x00000088
+         mmcqd/0-82    [000] ...1    56.879190: mmc_blk_rw_start: cmd=18,addr=0x001cec48,size=0x00000100
+          <idle>-0     [000] ..s3    56.880192: mmc_blk_rw_end: cmd=18,addr=0x001cec48,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.880782: mmc_blk_rw_start: cmd=18,addr=0x001d11c8,size=0x000000f0
+          <idle>-0     [000] ..s3    56.881750: mmc_blk_rw_end: cmd=18,addr=0x001d11c8,size=0x000000f0
+         mmcqd/0-82    [000] ...1    56.882143: mmc_blk_rw_start: cmd=18,addr=0x001ccb30,size=0x00000100
+        Compiler-387   [000] ..s2    56.883123: mmc_blk_rw_end: cmd=18,addr=0x001ccb30,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.884709: mmc_blk_rw_start: cmd=18,addr=0x001cefb8,size=0x000000d0
+          <idle>-0     [000] ..s3    56.885617: mmc_blk_rw_end: cmd=18,addr=0x001cefb8,size=0x000000d0
+         mmcqd/0-82    [000] ...1    56.885963: mmc_blk_rw_start: cmd=18,addr=0x001cc598,size=0x00000090
+          <idle>-0     [000] ..s3    56.886669: mmc_blk_rw_end: cmd=18,addr=0x001cc598,size=0x00000090
+         mmcqd/0-82    [000] ...1    56.886972: mmc_blk_rw_start: cmd=18,addr=0x001cf088,size=0x00000098
+           <...>-1488  [000] ..s3    56.887678: mmc_blk_rw_end: cmd=18,addr=0x001cf088,size=0x00000098
+         mmcqd/0-82    [000] ...1    56.887794: mmc_blk_rw_start: cmd=18,addr=0x001cf660,size=0x00000100
+          <idle>-0     [000] ..s3    56.888813: mmc_blk_rw_end: cmd=18,addr=0x001cf660,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.888906: mmc_blk_rw_start: cmd=18,addr=0x00b88260,size=0x00000008
+          <idle>-0     [000] ..s3    56.889033: mmc_blk_rw_end: cmd=18,addr=0x00b88260,size=0x00000008
+         mmcqd/0-82    [000] ...1    56.889423: mmc_blk_rw_start: cmd=18,addr=0x001d45e8,size=0x00000100
+          <idle>-0     [000] ..s3    56.890499: mmc_blk_rw_end: cmd=18,addr=0x001d45e8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.891533: mmc_blk_rw_start: cmd=18,addr=0x001ce380,size=0x000000d0
+          <idle>-0     [000] ..s3    56.892387: mmc_blk_rw_end: cmd=18,addr=0x001ce380,size=0x000000d0
+         mmcqd/0-82    [000] ...1    56.893152: mmc_blk_rw_start: cmd=18,addr=0x001d8e10,size=0x000000b0
+          <idle>-0     [000] ..s3    56.893861: mmc_blk_rw_end: cmd=18,addr=0x001d8e10,size=0x000000b0
+         mmcqd/0-82    [000] ...1    56.894806: mmc_blk_rw_start: cmd=18,addr=0x00544c90,size=0x00000100
+          <idle>-0     [000] ..s3    56.895846: mmc_blk_rw_end: cmd=18,addr=0x00544c90,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.896175: mmc_blk_rw_start: cmd=18,addr=0x005441a8,size=0x00000100
+          <idle>-0     [000] ..s3    56.897158: mmc_blk_rw_end: cmd=18,addr=0x005441a8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.897495: mmc_blk_rw_start: cmd=18,addr=0x001d9dc8,size=0x00000100
+          <idle>-0     [000] ..s3    56.898518: mmc_blk_rw_end: cmd=18,addr=0x001d9dc8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.898781: mmc_blk_rw_start: cmd=18,addr=0x001d5798,size=0x000000a0
+   WindowManager-396   [000] ..s2    56.899508: mmc_blk_rw_end: cmd=18,addr=0x001d5798,size=0x000000a0
+         mmcqd/0-82    [000] ...1    56.900612: mmc_blk_rw_start: cmd=18,addr=0x001d3140,size=0x00000100
+   WindowManager-396   [000] ..s2    56.901656: mmc_blk_rw_end: cmd=18,addr=0x001d3140,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.901925: mmc_blk_rw_start: cmd=18,addr=0x001d6530,size=0x00000100
+           <...>-204   [000] ..s2    56.902901: mmc_blk_rw_end: cmd=18,addr=0x001d6530,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.903030: mmc_blk_rw_start: cmd=18,addr=0x001d8320,size=0x00000100
+          <idle>-0     [000] ..s3    56.903994: mmc_blk_rw_end: cmd=18,addr=0x001d8320,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.904278: mmc_blk_rw_start: cmd=18,addr=0x001d9d20,size=0x000000a8
+          <idle>-0     [000] ..s3    56.904943: mmc_blk_rw_end: cmd=18,addr=0x001d9d20,size=0x000000a8
+         mmcqd/0-82    [000] ...1    56.906275: mmc_blk_rw_start: cmd=18,addr=0x005449e0,size=0x00000100
+          <idle>-0     [000] ..s3    56.907247: mmc_blk_rw_end: cmd=18,addr=0x005449e0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.907674: mmc_blk_rw_start: cmd=18,addr=0x005437c0,size=0x00000100
+          <idle>-0     [000] ..s3    56.908631: mmc_blk_rw_end: cmd=18,addr=0x005437c0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.910838: mmc_blk_rw_start: cmd=18,addr=0x001ccd78,size=0x000000c0
+          <idle>-0     [000] ..s3    56.911723: mmc_blk_rw_end: cmd=18,addr=0x001ccd78,size=0x000000c0
+         mmcqd/0-82    [000] ...1    56.912234: mmc_blk_rw_start: cmd=18,addr=0x001d6278,size=0x000000b8
+          <idle>-0     [000] ..s3    56.912999: mmc_blk_rw_end: cmd=18,addr=0x001d6278,size=0x000000b8
+         mmcqd/0-82    [000] ...1    56.935470: mmc_blk_rw_start: cmd=18,addr=0x001cd370,size=0x00000100
+          <idle>-0     [000] ..s3    56.936581: mmc_blk_rw_end: cmd=18,addr=0x001cd370,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.937169: mmc_blk_rw_start: cmd=18,addr=0x001d3c70,size=0x000000f0
+          <idle>-0     [000] ..s3    56.938142: mmc_blk_rw_end: cmd=18,addr=0x001d3c70,size=0x000000f0
+         mmcqd/0-82    [000] ...1    56.939187: mmc_blk_rw_start: cmd=18,addr=0x001ceb98,size=0x000000b0
+          <idle>-0     [000] ..s3    56.940006: mmc_blk_rw_end: cmd=18,addr=0x001ceb98,size=0x000000b0
+         mmcqd/0-82    [000] ...1    56.940382: mmc_blk_rw_start: cmd=18,addr=0x001cdad8,size=0x00000100
+          <idle>-0     [000] ..s3    56.941418: mmc_blk_rw_end: cmd=18,addr=0x001cdad8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.941715: mmc_blk_rw_start: cmd=18,addr=0x001d3a90,size=0x00000018
+          <idle>-0     [000] ..s3    56.941974: mmc_blk_rw_end: cmd=18,addr=0x001d3a90,size=0x00000018
+         mmcqd/0-82    [000] ...1    56.942388: mmc_blk_rw_start: cmd=18,addr=0x001cf850,size=0x00000100
+          <idle>-0     [000] ..s3    56.943362: mmc_blk_rw_end: cmd=18,addr=0x001cf850,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.943778: mmc_blk_rw_start: cmd=18,addr=0x001cc828,size=0x000000c8
+          <idle>-0     [000] ..s3    56.944676: mmc_blk_rw_end: cmd=18,addr=0x001cc828,size=0x000000c8
+         mmcqd/0-82    [000] ...1    56.945026: mmc_blk_rw_start: cmd=18,addr=0x001d0358,size=0x00000100
+          <idle>-0     [000] ..s3    56.946053: mmc_blk_rw_end: cmd=18,addr=0x001d0358,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.946416: mmc_blk_rw_start: cmd=18,addr=0x001d3e60,size=0x000000a8
+          <idle>-0     [000] ..s3    56.947118: mmc_blk_rw_end: cmd=18,addr=0x001d3e60,size=0x000000a8
+         mmcqd/0-82    [000] ...1    56.947455: mmc_blk_rw_start: cmd=18,addr=0x001d40c8,size=0x00000100
+          <idle>-0     [000] ..s3    56.948489: mmc_blk_rw_end: cmd=18,addr=0x001d40c8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.948831: mmc_blk_rw_start: cmd=18,addr=0x001d41f0,size=0x00000100
+          <idle>-0     [000] ..s3    56.949854: mmc_blk_rw_end: cmd=18,addr=0x001d41f0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.950189: mmc_blk_rw_start: cmd=18,addr=0x001d3f08,size=0x00000088
+          <idle>-0     [000] ..s3    56.950786: mmc_blk_rw_end: cmd=18,addr=0x001d3f08,size=0x00000088
+         mmcqd/0-82    [000] ...1    56.951156: mmc_blk_rw_start: cmd=18,addr=0x001d4460,size=0x00000100
+          <idle>-0     [000] ..s3    56.952161: mmc_blk_rw_end: cmd=18,addr=0x001d4460,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.954210: mmc_blk_rw_start: cmd=18,addr=0x001d1c90,size=0x000000e0
+          <idle>-0     [000] .Ns3    56.955120: mmc_blk_rw_end: cmd=18,addr=0x001d1c90,size=0x000000e0
+         mmcqd/0-82    [000] ...1    56.956111: mmc_blk_rw_start: cmd=18,addr=0x001d1db8,size=0x00000100
+        Compiler-1495  [000] ..s2    56.957170: mmc_blk_rw_end: cmd=18,addr=0x001d1db8,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.958861: mmc_blk_rw_start: cmd=18,addr=0x001ccc30,size=0x00000100
+        Compiler-1495  [000] ..s2    56.959885: mmc_blk_rw_end: cmd=18,addr=0x001ccc30,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.960795: mmc_blk_rw_start: cmd=18,addr=0x001cd0a0,size=0x00000100
+          <idle>-0     [000] ..s3    56.961838: mmc_blk_rw_end: cmd=18,addr=0x001cd0a0,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.965080: mmc_blk_rw_start: cmd=18,addr=0x001cfc08,size=0x00000100
+           <...>-1534  [000] ..s3    56.966104: mmc_blk_rw_end: cmd=18,addr=0x001cfc08,size=0x00000100
+         mmcqd/0-82    [000] ...1    56.969245: mmc_blk_rw_start: cmd=18,addr=0x001d1d70,size=0x00000048
+           <...>-1534  [000] ..s2    56.969681: mmc_blk_rw_end: cmd=18,addr=0x001d1d70,size=0x00000048
+         mmcqd/0-82    [000] ...1    56.978217: mmc_blk_rw_start: cmd=18,addr=0x001d19f8,size=0x000000b8
+           <...>-1534  [000] ..s4    56.979048: mmc_blk_rw_end: cmd=18,addr=0x001d19f8,size=0x000000b8
+         mmcqd/0-82    [000] ...1    56.989267: mmc_blk_rw_start: cmd=18,addr=0x00545fd0,size=0x00000100
+          <idle>-0     [000] ..s3    56.990384: mmc_blk_rw_end: cmd=18,addr=0x00545fd0,size=0x00000100
+         mmcqd/0-82    [001] ...1    56.990930: mmc_blk_rw_start: cmd=18,addr=0x001ceb00,size=0x00000098
+          <idle>-0     [000] ..s3    56.991576: mmc_blk_rw_end: cmd=18,addr=0x001ceb00,size=0x00000098
+         mmcqd/0-82    [000] ...1    56.997991: mmc_blk_rw_start: cmd=18,addr=0x001cf760,size=0x00000080
+          <idle>-0     [000] ..s3    56.998591: mmc_blk_rw_end: cmd=18,addr=0x001cf760,size=0x00000080
+         mmcqd/0-82    [000] ...1    56.999603: mmc_blk_rw_start: cmd=18,addr=0x001d0458,size=0x000000c8
+          <idle>-0     [000] ..s3    57.000459: mmc_blk_rw_end: cmd=18,addr=0x001d0458,size=0x000000c8
+         mmcqd/0-82    [000] ...1    57.000920: mmc_blk_rw_start: cmd=18,addr=0x001d2680,size=0x00000100
+          <idle>-0     [000] ..s3    57.001914: mmc_blk_rw_end: cmd=18,addr=0x001d2680,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.002233: mmc_blk_rw_start: cmd=18,addr=0x001cf4a8,size=0x00000088
+          <idle>-0     [000] ..s3    57.002917: mmc_blk_rw_end: cmd=18,addr=0x001cf4a8,size=0x00000088
+         mmcqd/0-82    [000] ...1    57.003455: mmc_blk_rw_start: cmd=18,addr=0x001cf220,size=0x00000020
+          <idle>-0     [000] ..s3    57.003677: mmc_blk_rw_end: cmd=18,addr=0x001cf220,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.004798: mmc_blk_rw_start: cmd=18,addr=0x001d7ae8,size=0x00000100
+          <idle>-0     [000] ..s3    57.005940: mmc_blk_rw_end: cmd=18,addr=0x001d7ae8,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.006242: mmc_blk_rw_start: cmd=18,addr=0x001d8420,size=0x00000088
+          <idle>-0     [000] ..s3    57.006811: mmc_blk_rw_end: cmd=18,addr=0x001d8420,size=0x00000088
+         mmcqd/0-82    [000] ...1    57.014360: mmc_blk_rw_start: cmd=18,addr=0x00b88258,size=0x00000008
+          <idle>-0     [000] ..s3    57.014509: mmc_blk_rw_end: cmd=18,addr=0x00b88258,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.015519: mmc_blk_rw_start: cmd=18,addr=0x001d41c8,size=0x00000028
+          <idle>-0     [000] ..s3    57.015851: mmc_blk_rw_end: cmd=18,addr=0x001d41c8,size=0x00000028
+         mmcqd/0-82    [000] ...1    57.016743: mmc_blk_rw_start: cmd=18,addr=0x001d22d8,size=0x00000100
+          <idle>-0     [000] ..s3    57.017853: mmc_blk_rw_end: cmd=18,addr=0x001d22d8,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.018187: mmc_blk_rw_start: cmd=18,addr=0x001d3c30,size=0x00000040
+          <idle>-0     [000] ..s3    57.018535: mmc_blk_rw_end: cmd=18,addr=0x001d3c30,size=0x00000040
+         mmcqd/0-82    [000] ...1    57.019173: mmc_blk_rw_start: cmd=18,addr=0x001cdbd8,size=0x00000080
+          <idle>-0     [000] ..s3    57.019773: mmc_blk_rw_end: cmd=18,addr=0x001cdbd8,size=0x00000080
+         mmcqd/0-82    [000] ...1    57.020398: mmc_blk_rw_start: cmd=18,addr=0x001d4560,size=0x00000088
+          <idle>-0     [000] ..s3    57.020992: mmc_blk_rw_end: cmd=18,addr=0x001d4560,size=0x00000088
+         mmcqd/0-82    [000] ...1    57.022153: mmc_blk_rw_start: cmd=18,addr=0x001ced68,size=0x000000a0
+          <idle>-0     [000] ..s3    57.022895: mmc_blk_rw_end: cmd=18,addr=0x001ced68,size=0x000000a0
+         mmcqd/0-82    [000] ...1    57.023353: mmc_blk_rw_start: cmd=18,addr=0x001cca90,size=0x000000a0
+          <idle>-0     [000] ..s3    57.024100: mmc_blk_rw_end: cmd=18,addr=0x001cca90,size=0x000000a0
+         mmcqd/0-82    [000] ...1    57.025959: mmc_blk_rw_start: cmd=18,addr=0x00544ae0,size=0x00000098
+          <idle>-0     [000] ..s3    57.026594: mmc_blk_rw_end: cmd=18,addr=0x00544ae0,size=0x00000098
+         mmcqd/0-82    [000] ...1    57.027610: mmc_blk_rw_start: cmd=18,addr=0x001ce810,size=0x00000100
+          <idle>-0     [000] ..s3    57.028584: mmc_blk_rw_end: cmd=18,addr=0x001ce810,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.028628: mmc_blk_rw_start: cmd=18,addr=0x001cd008,size=0x00000098
+           <...>-1488  [000] ..s2    57.029283: mmc_blk_rw_end: cmd=18,addr=0x001cd008,size=0x00000098
+         mmcqd/0-82    [000] ...1    57.029304: mmc_blk_rw_start: cmd=18,addr=0x001cca80,size=0x00000010
+           <...>-1531  [000] ..s2    57.029488: mmc_blk_rw_end: cmd=18,addr=0x001cca80,size=0x00000010
+         mmcqd/0-82    [000] ...1    57.034193: mmc_blk_rw_start: cmd=18,addr=0x001ccd30,size=0x00000048
+          <idle>-0     [000] ..s3    57.034599: mmc_blk_rw_end: cmd=18,addr=0x001ccd30,size=0x00000048
+         mmcqd/0-82    [000] ...1    57.034644: mmc_blk_rw_start: cmd=18,addr=0x001d13b8,size=0x00000100
+          <idle>-0     [000] ..s3    57.035681: mmc_blk_rw_end: cmd=18,addr=0x001d13b8,size=0x00000100
+         mmcqd/0-82    [001] ...1    57.039204: mmc_blk_rw_start: cmd=18,addr=0x001cd680,size=0x00000090
+          <idle>-0     [000] ..s3    57.039835: mmc_blk_rw_end: cmd=18,addr=0x001cd680,size=0x00000090
+         mmcqd/0-82    [000] ...1    57.040145: mmc_blk_rw_start: cmd=18,addr=0x001d33a0,size=0x000000d8
+          <idle>-0     [000] ..s3    57.041015: mmc_blk_rw_end: cmd=18,addr=0x001d33a0,size=0x000000d8
+         mmcqd/0-82    [000] ...1    57.044216: mmc_blk_rw_start: cmd=25,addr=0x002c6530,size=0x00000048
+          <idle>-0     [000] ..s3    57.045285: mmc_blk_rw_end: cmd=25,addr=0x002c6530,size=0x00000048
+         mmcqd/0-82    [000] ...1    57.046053: mmc_blk_rw_start: cmd=25,addr=0x002c6578,size=0x00000008
+          <idle>-0     [000] ..s3    57.046113: mmc_blk_rw_end: cmd=25,addr=0x002c6578,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.046937: mmc_blk_rw_start: cmd=25,addr=0x002c6580,size=0x00000008
+          <idle>-0     [000] ..s3    57.046997: mmc_blk_rw_end: cmd=25,addr=0x002c6580,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.047945: mmc_blk_rw_start: cmd=25,addr=0x002c6588,size=0x00000030
+          <idle>-0     [000] ..s3    57.048141: mmc_blk_rw_end: cmd=25,addr=0x002c6588,size=0x00000030
+         mmcqd/0-82    [000] ...1    57.048855: mmc_blk_rw_start: cmd=25,addr=0x002c65b8,size=0x00000008
+          <idle>-0     [000] ..s3    57.048913: mmc_blk_rw_end: cmd=25,addr=0x002c65b8,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.049547: mmc_blk_rw_start: cmd=18,addr=0x001cead0,size=0x00000030
+          <idle>-0     [000] ..s3    57.049858: mmc_blk_rw_end: cmd=18,addr=0x001cead0,size=0x00000030
+         mmcqd/0-82    [000] ...1    57.050791: mmc_blk_rw_start: cmd=18,addr=0x001cd470,size=0x00000080
+          <idle>-0     [000] ..s3    57.051398: mmc_blk_rw_end: cmd=18,addr=0x001cd470,size=0x00000080
+         mmcqd/0-82    [000] ...1    57.054193: mmc_blk_rw_start: cmd=18,addr=0x00b88248,size=0x00000008
+           <...>-1488  [000] ..s2    57.054408: mmc_blk_rw_end: cmd=18,addr=0x00b88248,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.054487: mmc_blk_rw_start: cmd=18,addr=0x001ce1a0,size=0x00000090
+           <...>-1488  [000] ..s2    57.055128: mmc_blk_rw_end: cmd=18,addr=0x001ce1a0,size=0x00000090
+         mmcqd/0-82    [000] ...1    57.055512: mmc_blk_rw_start: cmd=18,addr=0x00b87298,size=0x00000008
+          <idle>-0     [000] ..s3    57.055640: mmc_blk_rw_end: cmd=18,addr=0x00b87298,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.055658: mmc_blk_rw_start: cmd=18,addr=0x00b91248,size=0x00000008
+          <idle>-0     [000] ..s3    57.055845: mmc_blk_rw_end: cmd=18,addr=0x00b91248,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.055894: mmc_blk_rw_start: cmd=18,addr=0x00b93138,size=0x00000008
+          <idle>-0     [000] ..s3    57.056031: mmc_blk_rw_end: cmd=18,addr=0x00b93138,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.056073: mmc_blk_rw_start: cmd=18,addr=0x001ce230,size=0x00000050
+           <...>-1488  [000] ..s2    57.056486: mmc_blk_rw_end: cmd=18,addr=0x001ce230,size=0x00000050
+         mmcqd/0-82    [000] ...1    57.056730: mmc_blk_rw_start: cmd=18,addr=0x00b93120,size=0x00000008
+          <idle>-0     [000] ..s3    57.056857: mmc_blk_rw_end: cmd=18,addr=0x00b93120,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.056946: mmc_blk_rw_start: cmd=18,addr=0x00b87290,size=0x00000008
+           <...>-1488  [000] ..s2    57.057066: mmc_blk_rw_end: cmd=18,addr=0x00b87290,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.057083: mmc_blk_rw_start: cmd=18,addr=0x00b88240,size=0x00000008
+           <...>-1488  [000] ..s3    57.057204: mmc_blk_rw_end: cmd=18,addr=0x00b88240,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.059204: mmc_blk_rw_start: cmd=18,addr=0x00544448,size=0x00000100
+          <idle>-0     [000] ..s3    57.060309: mmc_blk_rw_end: cmd=18,addr=0x00544448,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.060443: mmc_blk_rw_start: cmd=18,addr=0x001d53f8,size=0x00000028
+           <...>-1488  [000] ..s4    57.060791: mmc_blk_rw_end: cmd=18,addr=0x001d53f8,size=0x00000028
+         mmcqd/0-82    [000] ...1    57.061081: mmc_blk_rw_start: cmd=18,addr=0x001ced48,size=0x00000020
+          <idle>-0     [000] ..s3    57.061342: mmc_blk_rw_end: cmd=18,addr=0x001ced48,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.061580: mmc_blk_rw_start: cmd=18,addr=0x001ce668,size=0x00000100
+          <idle>-0     [000] ..s3    57.062605: mmc_blk_rw_end: cmd=18,addr=0x001ce668,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.062882: mmc_blk_rw_start: cmd=18,addr=0x001ce520,size=0x00000100
+          <idle>-0     [000] ..s3    57.063843: mmc_blk_rw_end: cmd=18,addr=0x001ce520,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.064177: mmc_blk_rw_start: cmd=25,addr=0x002c65c0,size=0x00000030
+           <...>-1488  [000] ..s2    57.064365: mmc_blk_rw_end: cmd=25,addr=0x002c65c0,size=0x00000030
+         mmcqd/0-82    [000] ...1    57.065042: mmc_blk_rw_start: cmd=25,addr=0x002c65f0,size=0x00000008
+           <...>-1488  [000] ..s3    57.065098: mmc_blk_rw_end: cmd=25,addr=0x002c65f0,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.066113: mmc_blk_rw_start: cmd=25,addr=0x002c65f8,size=0x00000030
+          <idle>-0     [000] .Ns3    57.066320: mmc_blk_rw_end: cmd=25,addr=0x002c65f8,size=0x00000030
+         mmcqd/0-82    [000] ...1    57.067085: mmc_blk_rw_start: cmd=25,addr=0x002c6628,size=0x00000008
+          <idle>-0     [000] ..s3    57.067144: mmc_blk_rw_end: cmd=25,addr=0x002c6628,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.067995: mmc_blk_rw_start: cmd=25,addr=0x00b98110,size=0x00000008
+          <idle>-0     [000] ..s3    57.068056: mmc_blk_rw_end: cmd=25,addr=0x00b98110,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.068894: mmc_blk_rw_start: cmd=25,addr=0x002c6630,size=0x00000020
+          <idle>-0     [000] ..s3    57.069029: mmc_blk_rw_end: cmd=25,addr=0x002c6630,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.069653: mmc_blk_rw_start: cmd=25,addr=0x002c6650,size=0x00000008
+          <idle>-0     [000] ..s3    57.069712: mmc_blk_rw_end: cmd=25,addr=0x002c6650,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.070613: mmc_blk_rw_start: cmd=25,addr=0x002c6658,size=0x00000030
+          <idle>-0     [000] ..s3    57.070798: mmc_blk_rw_end: cmd=25,addr=0x002c6658,size=0x00000030
+         mmcqd/0-82    [000] ...1    57.071612: mmc_blk_rw_start: cmd=25,addr=0x002c6688,size=0x00000008
+          <idle>-0     [000] ..s3    57.071670: mmc_blk_rw_end: cmd=25,addr=0x002c6688,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.072584: mmc_blk_rw_start: cmd=25,addr=0x00b98118,size=0x00000008
+          <idle>-0     [000] ..s3    57.072660: mmc_blk_rw_end: cmd=25,addr=0x00b98118,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.073492: mmc_blk_rw_start: cmd=25,addr=0x002c6690,size=0x00000020
+          <idle>-0     [000] ..s3    57.073643: mmc_blk_rw_end: cmd=25,addr=0x002c6690,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.074337: mmc_blk_rw_start: cmd=25,addr=0x002c66b0,size=0x00000008
+          <idle>-0     [000] ..s3    57.074413: mmc_blk_rw_end: cmd=25,addr=0x002c66b0,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.075439: mmc_blk_rw_start: cmd=25,addr=0x002c66b8,size=0x00000040
+          <idle>-0     [000] ..s3    57.075814: mmc_blk_rw_end: cmd=25,addr=0x002c66b8,size=0x00000040
+         mmcqd/0-82    [000] ...1    57.077220: mmc_blk_rw_start: cmd=25,addr=0x002c66f8,size=0x00000008
+          <idle>-0     [000] ..s3    57.077296: mmc_blk_rw_end: cmd=25,addr=0x002c66f8,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.078134: mmc_blk_rw_start: cmd=25,addr=0x002c6700,size=0x00000008
+          <idle>-0     [000] ..s3    57.078210: mmc_blk_rw_end: cmd=25,addr=0x002c6700,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.079207: mmc_blk_rw_start: cmd=18,addr=0x001cd810,size=0x000000b0
+          <idle>-0     [000] ..s3    57.079920: mmc_blk_rw_end: cmd=18,addr=0x001cd810,size=0x000000b0
+         mmcqd/0-82    [000] ...1    57.102577: mmc_blk_rw_start: cmd=18,addr=0x001d55a8,size=0x00000020
+          <idle>-0     [000] ..s3    57.102988: mmc_blk_rw_end: cmd=18,addr=0x001d55a8,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.105262: mmc_blk_rw_start: cmd=18,addr=0x00343b00,size=0x00000020
+           <...>-1488  [000] ..s2    57.105606: mmc_blk_rw_end: cmd=18,addr=0x00343b00,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.106150: mmc_blk_rw_start: cmd=18,addr=0x00b872a0,size=0x00000008
+           <...>-1488  [000] ..s2    57.106340: mmc_blk_rw_end: cmd=18,addr=0x00b872a0,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.106360: mmc_blk_rw_start: cmd=18,addr=0x00b912a0,size=0x00000008
+           <...>-1525  [000] ..s2    57.106549: mmc_blk_rw_end: cmd=18,addr=0x00b912a0,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.106745: mmc_blk_rw_start: cmd=18,addr=0x00343b78,size=0x00000008
+           <...>-1488  [000] ..s2    57.106876: mmc_blk_rw_end: cmd=18,addr=0x00343b78,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.107430: mmc_blk_rw_start: cmd=18,addr=0x00343b80,size=0x00000008
+           <...>-1488  [000] ..s2    57.107559: mmc_blk_rw_end: cmd=18,addr=0x00343b80,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.108843: mmc_blk_rw_start: cmd=18,addr=0x00343b20,size=0x00000040
+           <...>-1525  [000] ..s2    57.109237: mmc_blk_rw_end: cmd=18,addr=0x00343b20,size=0x00000040
+         mmcqd/0-82    [000] ...1    57.110414: mmc_blk_rw_start: cmd=18,addr=0x001cf530,size=0x00000030
+          <idle>-0     [000] ..s3    57.110809: mmc_blk_rw_end: cmd=18,addr=0x001cf530,size=0x00000030
+         mmcqd/0-82    [000] ...1    57.110880: mmc_blk_rw_start: cmd=18,addr=0x001cc028,size=0x00000100
+          <idle>-0     [000] ..s3    57.111960: mmc_blk_rw_end: cmd=18,addr=0x001cc028,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.112794: mmc_blk_rw_start: cmd=18,addr=0x001d14b8,size=0x00000100
+           <...>-1488  [000] ..s2    57.113838: mmc_blk_rw_end: cmd=18,addr=0x001d14b8,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.114825: mmc_blk_rw_start: cmd=18,addr=0x001d46e8,size=0x00000100
+           <...>-1488  [000] ..s2    57.115915: mmc_blk_rw_end: cmd=18,addr=0x001d46e8,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.115997: mmc_blk_rw_start: cmd=18,addr=0x001cd8c0,size=0x00000010
+           <...>-1488  [000] ..s3    57.116180: mmc_blk_rw_end: cmd=18,addr=0x001cd8c0,size=0x00000010
+         mmcqd/0-82    [000] ...1    57.119197: mmc_blk_rw_start: cmd=18,addr=0x00b91258,size=0x00000020
+           <...>-1529  [000] ..s2    57.119555: mmc_blk_rw_end: cmd=18,addr=0x00b91258,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.120544: mmc_blk_rw_start: cmd=18,addr=0x00b91250,size=0x00000008
+          <idle>-0     [000] .Ns4    57.120694: mmc_blk_rw_end: cmd=18,addr=0x00b91250,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.120710: mmc_blk_rw_start: cmd=18,addr=0x00b91360,size=0x00000018
+           <...>-1525  [000] ..s2    57.120911: mmc_blk_rw_end: cmd=18,addr=0x00b91360,size=0x00000018
+         mmcqd/0-82    [000] ...1    57.124398: mmc_blk_rw_start: cmd=18,addr=0x00b91278,size=0x00000010
+          <idle>-0     [000] ..s3    57.124605: mmc_blk_rw_end: cmd=18,addr=0x00b91278,size=0x00000010
+         mmcqd/0-82    [000] ...1    57.134837: mmc_blk_rw_start: cmd=18,addr=0x001d2840,size=0x00000100
+           <...>-1488  [000] ..s2    57.135881: mmc_blk_rw_end: cmd=18,addr=0x001d2840,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.138549: mmc_blk_rw_start: cmd=18,addr=0x001ce048,size=0x00000058
+           <...>-1523  [000] ..s2    57.139016: mmc_blk_rw_end: cmd=18,addr=0x001ce048,size=0x00000058
+         mmcqd/0-82    [000] ...1    57.139371: mmc_blk_rw_start: cmd=18,addr=0x001ce620,size=0x00000048
+        Binder_9-663   [000] ..s2    57.139720: mmc_blk_rw_end: cmd=18,addr=0x001ce620,size=0x00000048
+         mmcqd/0-82    [000] ...1    57.144191: mmc_blk_rw_start: cmd=18,addr=0x001d9468,size=0x000000d0
+          <idle>-0     [000] ..s3    57.145085: mmc_blk_rw_end: cmd=18,addr=0x001d9468,size=0x000000d0
+         mmcqd/0-82    [000] ...1    57.145455: mmc_blk_rw_start: cmd=18,addr=0x001d3f90,size=0x00000100
+          <idle>-0     [000] ..s3    57.146436: mmc_blk_rw_end: cmd=18,addr=0x001d3f90,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.146515: mmc_blk_rw_start: cmd=18,addr=0x001cdea0,size=0x000000a8
+          <idle>-0     [000] ..s3    57.147224: mmc_blk_rw_end: cmd=18,addr=0x001cdea0,size=0x000000a8
+         mmcqd/0-82    [000] ...1    57.152107: mmc_blk_rw_start: cmd=18,addr=0x005449a0,size=0x00000008
+           <...>-1488  [000] ..s2    57.152257: mmc_blk_rw_end: cmd=18,addr=0x005449a0,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.154192: mmc_blk_rw_start: cmd=18,addr=0x001d3040,size=0x00000100
+          <idle>-0     [000] ..s3    57.155162: mmc_blk_rw_end: cmd=18,addr=0x001d3040,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.162409: mmc_blk_rw_start: cmd=18,addr=0x0035a7e0,size=0x00000100
+           <...>-1488  [000] ..s2    57.163463: mmc_blk_rw_end: cmd=18,addr=0x0035a7e0,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.177438: mmc_blk_rw_start: cmd=18,addr=0x0013faa0,size=0x00000008
+          <idle>-0     [000] ..s3    57.177673: mmc_blk_rw_end: cmd=18,addr=0x0013faa0,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.204547: mmc_blk_rw_start: cmd=18,addr=0x001d9a88,size=0x00000100
+           <...>-1488  [000] ..s2    57.205593: mmc_blk_rw_end: cmd=18,addr=0x001d9a88,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.205939: mmc_blk_rw_start: cmd=18,addr=0x001d97d0,size=0x00000100
+           <...>-85    [000] ..s3    57.206922: mmc_blk_rw_end: cmd=18,addr=0x001d97d0,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.207744: mmc_blk_rw_start: cmd=18,addr=0x001d2780,size=0x000000a8
+          <idle>-0     [000] ..s3    57.208525: mmc_blk_rw_end: cmd=18,addr=0x001d2780,size=0x000000a8
+         mmcqd/0-82    [000] ...1    57.208869: mmc_blk_rw_start: cmd=18,addr=0x001d2940,size=0x00000100
+          <idle>-0     [000] ..s3    57.209819: mmc_blk_rw_end: cmd=18,addr=0x001d2940,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.209871: mmc_blk_rw_start: cmd=18,addr=0x001d2c78,size=0x00000100
+          <idle>-0     [000] ..s3    57.210890: mmc_blk_rw_end: cmd=18,addr=0x001d2c78,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.211390: mmc_blk_rw_start: cmd=18,addr=0x001d9ca8,size=0x00000078
+          <idle>-0     [000] ..s3    57.212014: mmc_blk_rw_end: cmd=18,addr=0x001d9ca8,size=0x00000078
+         mmcqd/0-82    [000] ...1    57.212429: mmc_blk_rw_start: cmd=18,addr=0x001d2a40,size=0x00000058
+          <idle>-0     [000] ..s3    57.212840: mmc_blk_rw_end: cmd=18,addr=0x001d2a40,size=0x00000058
+         mmcqd/0-82    [000] ...1    57.212887: mmc_blk_rw_start: cmd=18,addr=0x001d2b98,size=0x000000a0
+          <idle>-0     [000] ..s3    57.213629: mmc_blk_rw_end: cmd=18,addr=0x001d2b98,size=0x000000a0
+         mmcqd/0-82    [000] ...1    57.214172: mmc_blk_rw_start: cmd=18,addr=0x0013fe48,size=0x00000008
+          <idle>-0     [000] ..s3    57.214305: mmc_blk_rw_end: cmd=18,addr=0x0013fe48,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.214405: mmc_blk_rw_start: cmd=18,addr=0x001d2828,size=0x00000018
+           <...>-1488  [000] ..s2    57.214626: mmc_blk_rw_end: cmd=18,addr=0x001d2828,size=0x00000018
+         mmcqd/0-82    [000] ...1    57.214992: mmc_blk_rw_start: cmd=18,addr=0x001d98d0,size=0x00000100
+          <idle>-0     [000] ..s3    57.215970: mmc_blk_rw_end: cmd=18,addr=0x001d98d0,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.216111: mmc_blk_rw_start: cmd=18,addr=0x001d99d0,size=0x000000b8
+          <idle>-0     [000] .Ns3    57.216876: mmc_blk_rw_end: cmd=18,addr=0x001d99d0,size=0x000000b8
+         mmcqd/0-82    [001] ...1    57.217019: mmc_blk_rw_start: cmd=18,addr=0x001d9b88,size=0x00000020
+          <idle>-0     [000] ..s3    57.217344: mmc_blk_rw_end: cmd=18,addr=0x001d9b88,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.218411: mmc_blk_rw_start: cmd=18,addr=0x001d42f0,size=0x00000090
+          <idle>-0     [000] ..s3    57.219073: mmc_blk_rw_end: cmd=18,addr=0x001d42f0,size=0x00000090
+         mmcqd/0-82    [000] ...1    57.219314: mmc_blk_rw_start: cmd=18,addr=0x001d2ef0,size=0x000000b0
+          <idle>-0     [000] ..s3    57.220056: mmc_blk_rw_end: cmd=18,addr=0x001d2ef0,size=0x000000b0
+         mmcqd/0-82    [000] ...1    57.220313: mmc_blk_rw_start: cmd=18,addr=0x001d4380,size=0x000000e0
+          <idle>-0     [000] ..s3    57.221180: mmc_blk_rw_end: cmd=18,addr=0x001d4380,size=0x000000e0
+         mmcqd/0-82    [000] ...1    57.221384: mmc_blk_rw_start: cmd=18,addr=0x001d2fa0,size=0x000000a0
+          <idle>-0     [000] ..s3    57.222072: mmc_blk_rw_end: cmd=18,addr=0x001d2fa0,size=0x000000a0
+         mmcqd/0-82    [000] ...1    57.223422: mmc_blk_rw_start: cmd=18,addr=0x001cbf80,size=0x000000a8
+          <idle>-0     [000] ..s3    57.224200: mmc_blk_rw_end: cmd=18,addr=0x001cbf80,size=0x000000a8
+         mmcqd/0-82    [000] ...1    57.224509: mmc_blk_rw_start: cmd=18,addr=0x001d0098,size=0x00000100
+          <idle>-0     [000] ..s3    57.225557: mmc_blk_rw_end: cmd=18,addr=0x001d0098,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.225794: mmc_blk_rw_start: cmd=18,addr=0x001cff78,size=0x00000100
+          <idle>-0     [000] ..s3    57.226801: mmc_blk_rw_end: cmd=18,addr=0x001cff78,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.227092: mmc_blk_rw_start: cmd=18,addr=0x001d0078,size=0x00000020
+          <idle>-0     [000] ..s3    57.227402: mmc_blk_rw_end: cmd=18,addr=0x001d0078,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.227628: mmc_blk_rw_start: cmd=18,addr=0x001d9130,size=0x00000090
+          <idle>-0     [000] ..s3    57.228243: mmc_blk_rw_end: cmd=18,addr=0x001d9130,size=0x00000090
+         mmcqd/0-82    [000] ...1    57.228522: mmc_blk_rw_start: cmd=18,addr=0x001cf958,size=0x00000100
+          <idle>-0     [000] ..s3    57.229530: mmc_blk_rw_end: cmd=18,addr=0x001cf958,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.229794: mmc_blk_rw_start: cmd=18,addr=0x001d0288,size=0x000000d0
+          <idle>-0     [000] ..s3    57.230655: mmc_blk_rw_end: cmd=18,addr=0x001d0288,size=0x000000d0
+         mmcqd/0-82    [000] ...1    57.230854: mmc_blk_rw_start: cmd=18,addr=0x001cf7e0,size=0x00000070
+          <idle>-0     [000] ..s3    57.231357: mmc_blk_rw_end: cmd=18,addr=0x001cf7e0,size=0x00000070
+         mmcqd/0-82    [000] ...1    57.232991: mmc_blk_rw_start: cmd=18,addr=0x001d16d0,size=0x00000068
+          <idle>-0     [000] ..s3    57.233489: mmc_blk_rw_end: cmd=18,addr=0x001d16d0,size=0x00000068
+         mmcqd/0-82    [000] ...1    57.233879: mmc_blk_rw_start: cmd=18,addr=0x001cdc58,size=0x00000010
+          <idle>-0     [000] ..s3    57.234057: mmc_blk_rw_end: cmd=18,addr=0x001cdc58,size=0x00000010
+         mmcqd/0-82    [000] ...1    57.234417: mmc_blk_rw_start: cmd=18,addr=0x001d01a0,size=0x000000e8
+          <idle>-0     [000] ..s3    57.235343: mmc_blk_rw_end: cmd=18,addr=0x001d01a0,size=0x000000e8
+         mmcqd/0-82    [000] ...1    57.235572: mmc_blk_rw_start: cmd=18,addr=0x001d0578,size=0x000000d8
+          <idle>-0     [000] ..s3    57.236437: mmc_blk_rw_end: cmd=18,addr=0x001d0578,size=0x000000d8
+         mmcqd/0-82    [000] ...1    57.238214: mmc_blk_rw_start: cmd=18,addr=0x001cd1a0,size=0x000000c8
+          <idle>-0     [000] ..s3    57.239060: mmc_blk_rw_end: cmd=18,addr=0x001cd1a0,size=0x000000c8
+         mmcqd/0-82    [001] ...1    57.239429: mmc_blk_rw_start: cmd=18,addr=0x001cc8f0,size=0x00000090
+          <idle>-0     [000] ..s3    57.240094: mmc_blk_rw_end: cmd=18,addr=0x001cc8f0,size=0x00000090
+         mmcqd/0-82    [000] ...1    57.240493: mmc_blk_rw_start: cmd=18,addr=0x001d9008,size=0x00000100
+          <idle>-0     [000] ..s3    57.241469: mmc_blk_rw_end: cmd=18,addr=0x001d9008,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.243860: mmc_blk_rw_start: cmd=18,addr=0x001d1838,size=0x000000a0
+          <idle>-0     [000] ..s3    57.244560: mmc_blk_rw_end: cmd=18,addr=0x001d1838,size=0x000000a0
+         mmcqd/0-82    [000] ...1    57.245037: mmc_blk_rw_start: cmd=18,addr=0x001cd268,size=0x000000e0
+          <idle>-0     [000] ..s3    57.245971: mmc_blk_rw_end: cmd=18,addr=0x001cd268,size=0x000000e0
+         mmcqd/0-82    [000] ...1    57.246252: mmc_blk_rw_start: cmd=18,addr=0x001cddc8,size=0x000000d8
+          <idle>-0     [000] ..s3    57.247134: mmc_blk_rw_end: cmd=18,addr=0x001cddc8,size=0x000000d8
+         mmcqd/0-82    [000] ...1    57.247428: mmc_blk_rw_start: cmd=18,addr=0x001d4090,size=0x00000038
+          <idle>-0     [000] ..s3    57.247754: mmc_blk_rw_end: cmd=18,addr=0x001d4090,size=0x00000038
+         mmcqd/0-82    [000] ...1    57.247854: mmc_blk_rw_start: cmd=18,addr=0x001d0520,size=0x00000058
+          <idle>-0     [000] ..s3    57.248258: mmc_blk_rw_end: cmd=18,addr=0x001d0520,size=0x00000058
+         mmcqd/0-82    [000] ...1    57.248574: mmc_blk_rw_start: cmd=18,addr=0x001cfd08,size=0x000000e8
+          <idle>-0     [000] ..s3    57.249475: mmc_blk_rw_end: cmd=18,addr=0x001cfd08,size=0x000000e8
+         mmcqd/0-82    [000] ...1    57.249726: mmc_blk_rw_start: cmd=18,addr=0x001cfaa8,size=0x00000100
+          <idle>-0     [000] ..s3    57.250796: mmc_blk_rw_end: cmd=18,addr=0x001cfaa8,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.251114: mmc_blk_rw_start: cmd=18,addr=0x001cfba8,size=0x00000060
+          <idle>-0     [000] ..s3    57.251695: mmc_blk_rw_end: cmd=18,addr=0x001cfba8,size=0x00000060
+         mmcqd/0-82    [000] ...1    57.252516: mmc_blk_rw_start: cmd=18,addr=0x001cfdf0,size=0x00000100
+          <idle>-0     [000] ..s3    57.253564: mmc_blk_rw_end: cmd=18,addr=0x001cfdf0,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.253905: mmc_blk_rw_start: cmd=18,addr=0x001ce450,size=0x000000b0
+          <idle>-0     [000] ..s3    57.254612: mmc_blk_rw_end: cmd=18,addr=0x001ce450,size=0x000000b0
+         mmcqd/0-82    [000] ...1    57.255259: mmc_blk_rw_start: cmd=18,addr=0x001d0198,size=0x00000008
+          <idle>-0     [000] ..s3    57.255413: mmc_blk_rw_end: cmd=18,addr=0x001d0198,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.256613: mmc_blk_rw_start: cmd=18,addr=0x001d1f28,size=0x00000100
+          <idle>-0     [000] ..s3    57.257654: mmc_blk_rw_end: cmd=18,addr=0x001d1f28,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.259196: mmc_blk_rw_start: cmd=18,addr=0x0013fe08,size=0x00000040
+          <idle>-0     [000] ..s3    57.259737: mmc_blk_rw_end: cmd=18,addr=0x0013fe08,size=0x00000040
+         mmcqd/0-82    [000] ...1    57.259779: mmc_blk_rw_start: cmd=18,addr=0x0013fe50,size=0x00000018
+          <idle>-0     [000] ..s3    57.260033: mmc_blk_rw_end: cmd=18,addr=0x0013fe50,size=0x00000018
+         mmcqd/0-82    [000] ...1    57.260076: mmc_blk_rw_start: cmd=18,addr=0x001d0b78,size=0x00000100
+           <...>-1488  [000] ..s2    57.261095: mmc_blk_rw_end: cmd=18,addr=0x001d0b78,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.261370: mmc_blk_rw_start: cmd=18,addr=0x001d2c38,size=0x00000040
+           <...>-1488  [000] ..s2    57.261739: mmc_blk_rw_end: cmd=18,addr=0x001d2c38,size=0x00000040
+         mmcqd/0-82    [001] ...1    57.262839: mmc_blk_rw_start: cmd=18,addr=0x001d96c0,size=0x00000100
+           <...>-1488  [000] ..s2    57.263907: mmc_blk_rw_end: cmd=18,addr=0x001d96c0,size=0x00000100
+         mmcqd/0-82    [001] ...1    57.264945: mmc_blk_rw_start: cmd=18,addr=0x001d2440,size=0x00000100
+           <...>-1488  [000] ..s2    57.265992: mmc_blk_rw_end: cmd=18,addr=0x001d2440,size=0x00000100
+         mmcqd/0-82    [001] ...1    57.290040: mmc_blk_rw_start: cmd=18,addr=0x001d9678,size=0x00000048
+           <...>-1488  [000] ..s2    57.290472: mmc_blk_rw_end: cmd=18,addr=0x001d9678,size=0x00000048
+         mmcqd/0-82    [001] ...1    57.302592: mmc_blk_rw_start: cmd=18,addr=0x001cda70,size=0x00000068
+          <idle>-0     [000] ..s3    57.303140: mmc_blk_rw_end: cmd=18,addr=0x001cda70,size=0x00000068
+         mmcqd/0-82    [000] ...1    57.309317: mmc_blk_rw_start: cmd=18,addr=0x001d0a80,size=0x000000f8
+          <idle>-0     [000] ..s3    57.310291: mmc_blk_rw_end: cmd=18,addr=0x001d0a80,size=0x000000f8
+         mmcqd/0-82    [000] ...1    57.310613: mmc_blk_rw_start: cmd=18,addr=0x001d0df0,size=0x00000100
+          <idle>-0     [000] ..s3    57.311611: mmc_blk_rw_end: cmd=18,addr=0x001d0df0,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.311878: mmc_blk_rw_start: cmd=18,addr=0x001d0ef0,size=0x00000098
+          <idle>-0     [000] ..s3    57.312534: mmc_blk_rw_end: cmd=18,addr=0x001d0ef0,size=0x00000098
+         mmcqd/0-82    [000] ...1    57.315086: mmc_blk_rw_start: cmd=18,addr=0x001cfa58,size=0x00000050
+          <idle>-0     [000] ..s3    57.315561: mmc_blk_rw_end: cmd=18,addr=0x001cfa58,size=0x00000050
+         mmcqd/0-82    [000] ...1    57.316185: mmc_blk_rw_start: cmd=18,addr=0x001ce910,size=0x00000040
+           <...>-1523  [000] ..s2    57.316510: mmc_blk_rw_end: cmd=18,addr=0x001ce910,size=0x00000040
+         mmcqd/0-82    [000] ...1    57.319192: mmc_blk_rw_start: cmd=18,addr=0x001d0978,size=0x00000100
+          <idle>-0     [000] ..s3    57.320214: mmc_blk_rw_end: cmd=18,addr=0x001d0978,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.320264: mmc_blk_rw_start: cmd=18,addr=0x001d0c78,size=0x00000100
+           <...>-1523  [000] ..s2    57.321292: mmc_blk_rw_end: cmd=18,addr=0x001d0c78,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.323769: mmc_blk_rw_start: cmd=18,addr=0x001d2d78,size=0x00000078
+          <idle>-0     [000] ..s3    57.324361: mmc_blk_rw_end: cmd=18,addr=0x001d2d78,size=0x00000078
+         mmcqd/0-82    [000] ...1    57.327321: mmc_blk_rw_start: cmd=18,addr=0x001cc3d0,size=0x00000020
+           <...>-1523  [000] ..s2    57.327591: mmc_blk_rw_end: cmd=18,addr=0x001cc3d0,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.327617: mmc_blk_rw_start: cmd=18,addr=0x001cd5f0,size=0x00000090
+          <idle>-0     [000] ..s3    57.328264: mmc_blk_rw_end: cmd=18,addr=0x001cd5f0,size=0x00000090
+         mmcqd/0-82    [000] ...1    57.328300: mmc_blk_rw_start: cmd=18,addr=0x001ce500,size=0x00000020
+          <idle>-0     [000] ..s3    57.328518: mmc_blk_rw_end: cmd=18,addr=0x001ce500,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.371192: mmc_blk_rw_start: cmd=18,addr=0x001d2178,size=0x00000100
+           <...>-1488  [000] ..s2    57.372229: mmc_blk_rw_end: cmd=18,addr=0x001d2178,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.372428: mmc_blk_rw_start: cmd=18,addr=0x001d2278,size=0x00000060
+           <...>-1488  [000] ..s2    57.372913: mmc_blk_rw_end: cmd=18,addr=0x001d2278,size=0x00000060
+         mmcqd/0-82    [000] ...1    57.382172: mmc_blk_rw_start: cmd=18,addr=0x001d18d8,size=0x00000100
+           <...>-1547  [000] ..s2    57.383225: mmc_blk_rw_end: cmd=18,addr=0x001d18d8,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.391840: mmc_blk_rw_start: cmd=18,addr=0x001d1eb8,size=0x00000070
+           <...>-1488  [000] ..s2    57.392423: mmc_blk_rw_end: cmd=18,addr=0x001d1eb8,size=0x00000070
+         mmcqd/0-82    [000] ...1    57.394518: mmc_blk_rw_start: cmd=18,addr=0x00545750,size=0x00000100
+           <...>-1488  [000] ..s2    57.395564: mmc_blk_rw_end: cmd=18,addr=0x00545750,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.396101: mmc_blk_rw_start: cmd=18,addr=0x00545850,size=0x00000100
+           <...>-1545  [000] ..s2    57.397066: mmc_blk_rw_end: cmd=18,addr=0x00545850,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.397915: mmc_blk_rw_start: cmd=18,addr=0x00545950,size=0x00000100
+        Binder_A-669   [000] ..s2    57.398901: mmc_blk_rw_end: cmd=18,addr=0x00545950,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.429423: mmc_blk_rw_start: cmd=18,addr=0x00344700,size=0x00000020
+           <...>-1559  [000] ..s4    57.429771: mmc_blk_rw_end: cmd=18,addr=0x00344700,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.430206: mmc_blk_rw_start: cmd=18,addr=0x00344720,size=0x00000040
+           <...>-1559  [000] ..s4    57.430606: mmc_blk_rw_end: cmd=18,addr=0x00344720,size=0x00000040
+         mmcqd/0-82    [000] ...1    57.430705: mmc_blk_rw_start: cmd=18,addr=0x00344760,size=0x00000080
+           <...>-1559  [000] ..s3    57.431313: mmc_blk_rw_end: cmd=18,addr=0x00344760,size=0x00000080
+         mmcqd/0-82    [000] ...1    57.431392: mmc_blk_rw_start: cmd=18,addr=0x003447e0,size=0x00000020
+           <...>-1488  [000] ..s3    57.431645: mmc_blk_rw_end: cmd=18,addr=0x003447e0,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.434201: mmc_blk_rw_start: cmd=18,addr=0x00343f00,size=0x00000020
+           <...>-1488  [000] ..s2    57.434457: mmc_blk_rw_end: cmd=18,addr=0x00343f00,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.434904: mmc_blk_rw_start: cmd=18,addr=0x00b91298,size=0x00000008
+           <...>-1488  [000] ..s2    57.435094: mmc_blk_rw_end: cmd=18,addr=0x00b91298,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.435116: mmc_blk_rw_start: cmd=18,addr=0x00b914b0,size=0x00000010
+           <...>-1488  [000] ..s2    57.435277: mmc_blk_rw_end: cmd=18,addr=0x00b914b0,size=0x00000010
+         mmcqd/0-82    [000] ...1    57.436381: mmc_blk_rw_start: cmd=18,addr=0x00343f20,size=0x00000040
+           <...>-1488  [000] ..s2    57.436784: mmc_blk_rw_end: cmd=18,addr=0x00343f20,size=0x00000040
+         mmcqd/0-82    [000] ...1    57.436813: mmc_blk_rw_start: cmd=18,addr=0x00343f60,size=0x00000060
+           <...>-1488  [000] ..s2    57.437329: mmc_blk_rw_end: cmd=18,addr=0x00343f60,size=0x00000060
+         mmcqd/0-82    [000] ...1    57.439210: mmc_blk_rw_start: cmd=18,addr=0x001d0f88,size=0x00000098
+           <...>-1488  [000] ..s2    57.439983: mmc_blk_rw_end: cmd=18,addr=0x001d0f88,size=0x00000098
+         mmcqd/0-82    [000] ...1    57.458813: mmc_blk_rw_start: cmd=18,addr=0x00b912b0,size=0x00000020
+           <...>-1523  [000] ..s2    57.459127: mmc_blk_rw_end: cmd=18,addr=0x00b912b0,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.459557: mmc_blk_rw_start: cmd=18,addr=0x00b912a8,size=0x00000008
+           <...>-1557  [000] ..s2    57.459684: mmc_blk_rw_end: cmd=18,addr=0x00b912a8,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.459704: mmc_blk_rw_start: cmd=18,addr=0x001d6630,size=0x000000a0
+           <...>-1557  [000] ..s3    57.460432: mmc_blk_rw_end: cmd=18,addr=0x001d6630,size=0x000000a0
+         mmcqd/0-82    [000] ...1    57.460733: mmc_blk_rw_start: cmd=18,addr=0x001d3240,size=0x00000080
+           <...>-1557  [000] ..s2    57.461264: mmc_blk_rw_end: cmd=18,addr=0x001d3240,size=0x00000080
+         mmcqd/0-82    [000] ...1    57.464247: mmc_blk_rw_start: cmd=18,addr=0x00b912d0,size=0x00000010
+           <...>-1523  [000] ..s2    57.464441: mmc_blk_rw_end: cmd=18,addr=0x00b912d0,size=0x00000010
+         mmcqd/0-82    [000] ...1    57.464469: mmc_blk_rw_start: cmd=18,addr=0x00b912e8,size=0x00000020
+           <...>-1523  [000] ..s2    57.464789: mmc_blk_rw_end: cmd=18,addr=0x00b912e8,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.466611: mmc_blk_rw_start: cmd=18,addr=0x00b912e0,size=0x00000008
+           <...>-1523  [000] ..s2    57.466763: mmc_blk_rw_end: cmd=18,addr=0x00b912e0,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.485203: mmc_blk_rw_start: cmd=18,addr=0x00543ab8,size=0x00000100
+           <...>-1557  [000] ..s3    57.486350: mmc_blk_rw_end: cmd=18,addr=0x00543ab8,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.487748: mmc_blk_rw_start: cmd=18,addr=0x00543da8,size=0x00000100
+           <...>-1523  [000] ..s2    57.488841: mmc_blk_rw_end: cmd=18,addr=0x00543da8,size=0x00000100
+         mmcqd/0-82    [000] ...1    57.498275: mmc_blk_rw_start: cmd=18,addr=0x00543a20,size=0x00000098
+        Binder_2-130   [000] ..s2    57.499041: mmc_blk_rw_end: cmd=18,addr=0x00543a20,size=0x00000098
+         mmcqd/0-82    [000] ...1    57.515152: mmc_blk_rw_start: cmd=18,addr=0x001cd348,size=0x00000028
+           <...>-1559  [000] ..s2    57.515467: mmc_blk_rw_end: cmd=18,addr=0x001cd348,size=0x00000028
+         mmcqd/0-82    [000] ...1    57.516495: mmc_blk_rw_start: cmd=18,addr=0x001d92c0,size=0x00000010
+           <...>-1559  [000] ..s3    57.516782: mmc_blk_rw_end: cmd=18,addr=0x001d92c0,size=0x00000010
+         mmcqd/0-82    [000] ...1    57.555361: mmc_blk_rw_start: cmd=18,addr=0x001d0d78,size=0x00000078
+           <...>-1488  [000] ..s2    57.555949: mmc_blk_rw_end: cmd=18,addr=0x001d0d78,size=0x00000078
+         mmcqd/0-82    [000] ...1    57.556157: mmc_blk_rw_start: cmd=18,addr=0x001cfef0,size=0x00000088
+        Compiler-1495  [000] ..s3    57.556774: mmc_blk_rw_end: cmd=18,addr=0x001cfef0,size=0x00000088
+         mmcqd/0-82    [000] ...1    57.565912: mmc_blk_rw_start: cmd=18,addr=0x001d32c0,size=0x000000c8
+           <...>-1557  [000] ..s3    57.566737: mmc_blk_rw_end: cmd=18,addr=0x001d32c0,size=0x000000c8
+         mmcqd/0-82    [000] ...1    57.614954: mmc_blk_rw_start: cmd=18,addr=0x001d0840,size=0x00000080
+           <...>-1559  [000] ..s3    57.615517: mmc_blk_rw_end: cmd=18,addr=0x001d0840,size=0x00000080
+         mmcqd/0-82    [000] ...1    57.648037: mmc_blk_rw_start: cmd=18,addr=0x001d19d8,size=0x00000020
+           <...>-1559  [000] ..s2    57.648383: mmc_blk_rw_end: cmd=18,addr=0x001d19d8,size=0x00000020
+         mmcqd/0-82    [000] ...1    57.693082: mmc_blk_rw_start: cmd=25,addr=0x00b98120,size=0x00000008
+          <idle>-0     [000] ..s3    57.693171: mmc_blk_rw_end: cmd=25,addr=0x00b98120,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.708695: mmc_blk_rw_start: cmd=25,addr=0x00b98128,size=0x00000008
+           <...>-1541  [000] ..s2    57.708790: mmc_blk_rw_end: cmd=25,addr=0x00b98128,size=0x00000008
+         mmcqd/0-82    [000] ...1    57.714395: mmc_blk_rw_start: cmd=25,addr=0x002c6708,size=0x00000068
+           <...>-1541  [000] ..s4    57.715838: mmc_blk_rw_end: cmd=25,addr=0x002c6708,size=0x00000068
+         mmcqd/0-82    [000] ...1    57.717987: mmc_blk_rw_start: cmd=25,addr=0x002c6770,size=0x00000008
+           <...>-1541  [000] ..s2    57.718057: mmc_blk_rw_end: cmd=25,addr=0x002c6770,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.084817: mmc_blk_rw_start: cmd=18,addr=0x001d81e8,size=0x00000100
+        Compiler-387   [000] ..s2    58.086066: mmc_blk_rw_end: cmd=18,addr=0x001d81e8,size=0x00000100
+         mmcqd/0-82    [000] ...1    58.088028: mmc_blk_rw_start: cmd=18,addr=0x001d59c8,size=0x00000100
+          <idle>-0     [000] ..s3    58.089180: mmc_blk_rw_end: cmd=18,addr=0x001d59c8,size=0x00000100
+         mmcqd/0-82    [000] ...1    58.090030: mmc_blk_rw_start: cmd=18,addr=0x001d5ae0,size=0x00000100
+          <idle>-0     [000] ..s3    58.091133: mmc_blk_rw_end: cmd=18,addr=0x001d5ae0,size=0x00000100
+         mmcqd/0-82    [000] ...1    58.092466: mmc_blk_rw_start: cmd=18,addr=0x001d61d8,size=0x000000a0
+          <idle>-0     [000] ..s3    58.093289: mmc_blk_rw_end: cmd=18,addr=0x001d61d8,size=0x000000a0
+         mmcqd/0-82    [000] ...1    58.094858: mmc_blk_rw_start: cmd=18,addr=0x001d5e20,size=0x00000100
+          <idle>-0     [000] ..s3    58.095933: mmc_blk_rw_end: cmd=18,addr=0x001d5e20,size=0x00000100
+         mmcqd/0-82    [000] ...1    58.097221: mmc_blk_rw_start: cmd=18,addr=0x001d5ac8,size=0x00000018
+          <idle>-0     [000] ..s3    58.097634: mmc_blk_rw_end: cmd=18,addr=0x001d5ac8,size=0x00000018
+         mmcqd/0-82    [000] ...1    58.575553: mmc_blk_rw_start: cmd=25,addr=0x002c6778,size=0x00000058
+          <idle>-0     [000] ..s3    58.576045: mmc_blk_rw_end: cmd=25,addr=0x002c6778,size=0x00000058
+         mmcqd/0-82    [000] ...1    58.578793: mmc_blk_rw_start: cmd=25,addr=0x002c67d0,size=0x00000008
+         mmcqd/0-82    [000] ..s3    58.578935: mmc_blk_rw_end: cmd=25,addr=0x002c67d0,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.580809: mmc_blk_rw_start: cmd=25,addr=0x002c67d8,size=0x00000008
+         mmcqd/0-82    [000] ..s2    58.580958: mmc_blk_rw_end: cmd=25,addr=0x002c67d8,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.583739: mmc_blk_rw_start: cmd=25,addr=0x002c67e0,size=0x00000030
+          <idle>-0     [000] ..s3    58.584041: mmc_blk_rw_end: cmd=25,addr=0x002c67e0,size=0x00000030
+         mmcqd/0-82    [000] ...1    58.585137: mmc_blk_rw_start: cmd=25,addr=0x002c6810,size=0x00000008
+     kworker/0:2-48    [000] ..s3    58.585311: mmc_blk_rw_end: cmd=25,addr=0x002c6810,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.588080: mmc_blk_rw_start: cmd=18,addr=0x00b93130,size=0x00000008
+          <idle>-0     [000] ..s3    58.588375: mmc_blk_rw_end: cmd=18,addr=0x00b93130,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.589839: mmc_blk_rw_start: cmd=18,addr=0x00b93128,size=0x00000008
+          <idle>-0     [000] ..s4    58.590078: mmc_blk_rw_end: cmd=18,addr=0x00b93128,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.594680: mmc_blk_rw_start: cmd=25,addr=0x002c6818,size=0x00000038
+          <idle>-0     [000] ..s3    58.595009: mmc_blk_rw_end: cmd=25,addr=0x002c6818,size=0x00000038
+         mmcqd/0-82    [000] ...1    58.596248: mmc_blk_rw_start: cmd=25,addr=0x002c6850,size=0x00000008
+         mmcqd/0-82    [000] ..s2    58.596389: mmc_blk_rw_end: cmd=25,addr=0x002c6850,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.599773: mmc_blk_rw_start: cmd=25,addr=0x002c6858,size=0x00000030
+          <idle>-0     [000] ..s3    58.600194: mmc_blk_rw_end: cmd=25,addr=0x002c6858,size=0x00000030
+         mmcqd/0-82    [000] ...1    58.601507: mmc_blk_rw_start: cmd=25,addr=0x002c6888,size=0x00000008
+     kworker/0:2-48    [000] ..s4    58.601625: mmc_blk_rw_end: cmd=25,addr=0x002c6888,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.604459: mmc_blk_rw_start: cmd=25,addr=0x00b991f0,size=0x00000008
+     kworker/0:2-48    [000] ..s4    58.604654: mmc_blk_rw_end: cmd=25,addr=0x00b991f0,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.609374: mmc_blk_rw_start: cmd=25,addr=0x002c6890,size=0x00000020
+          <idle>-0     [000] ..s3    58.609576: mmc_blk_rw_end: cmd=25,addr=0x002c6890,size=0x00000020
+         mmcqd/0-82    [000] ...1    58.610551: mmc_blk_rw_start: cmd=25,addr=0x002c68b0,size=0x00000008
+     kworker/0:2-48    [000] ..s4    58.610669: mmc_blk_rw_end: cmd=25,addr=0x002c68b0,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.612541: mmc_blk_rw_start: cmd=25,addr=0x002c68b8,size=0x00000030
+          <idle>-0     [000] ..s3    58.612794: mmc_blk_rw_end: cmd=25,addr=0x002c68b8,size=0x00000030
+         mmcqd/0-82    [000] ...1    58.613930: mmc_blk_rw_start: cmd=25,addr=0x002c68e8,size=0x00000008
+     kworker/0:2-48    [000] ..s4    58.614049: mmc_blk_rw_end: cmd=25,addr=0x002c68e8,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.615695: mmc_blk_rw_start: cmd=25,addr=0x00b991f8,size=0x00000008
+     kworker/0:2-48    [000] ..s4    58.615817: mmc_blk_rw_end: cmd=25,addr=0x00b991f8,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.617071: mmc_blk_rw_start: cmd=25,addr=0x002c68f0,size=0x00000020
+          <idle>-0     [000] ..s3    58.617275: mmc_blk_rw_end: cmd=25,addr=0x002c68f0,size=0x00000020
+         mmcqd/0-82    [000] ...1    58.618373: mmc_blk_rw_start: cmd=25,addr=0x002c6910,size=0x00000008
+          <idle>-0     [000] ..s3    58.618571: mmc_blk_rw_end: cmd=25,addr=0x002c6910,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.621280: mmc_blk_rw_start: cmd=25,addr=0x002c6918,size=0x00000048
+          <idle>-0     [000] ..s3    58.621673: mmc_blk_rw_end: cmd=25,addr=0x002c6918,size=0x00000048
+         mmcqd/0-82    [000] ...1    58.622708: mmc_blk_rw_start: cmd=25,addr=0x002c6960,size=0x00000008
+          <idle>-0     [000] ..s3    58.622821: mmc_blk_rw_end: cmd=25,addr=0x002c6960,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.624060: mmc_blk_rw_start: cmd=25,addr=0x002c6968,size=0x00000008
+          <idle>-0     [000] ..s4    58.624249: mmc_blk_rw_end: cmd=25,addr=0x002c6968,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.724886: mmc_blk_rw_start: cmd=18,addr=0x005439a0,size=0x00000010
+        Binder_1-391   [000] ..s2    58.725161: mmc_blk_rw_end: cmd=18,addr=0x005439a0,size=0x00000010
+         mmcqd/0-82    [000] ...1    58.741803: mmc_blk_rw_start: cmd=18,addr=0x005474b8,size=0x00000008
+        Compiler-1495  [000] ..s3    58.742041: mmc_blk_rw_end: cmd=18,addr=0x005474b8,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.774047: mmc_blk_rw_start: cmd=18,addr=0x00b91398,size=0x00000018
+          <idle>-0     [000] ..s3    58.774338: mmc_blk_rw_end: cmd=18,addr=0x00b91398,size=0x00000018
+         mmcqd/0-82    [000] ...1    58.774417: mmc_blk_rw_start: cmd=18,addr=0x00b913c0,size=0x00000008
+           <...>-1563  [000] ..s2    58.774583: mmc_blk_rw_end: cmd=18,addr=0x00b913c0,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.778354: mmc_blk_rw_start: cmd=18,addr=0x00b913b0,size=0x00000010
+          <idle>-0     [000] .Ns3    58.778590: mmc_blk_rw_end: cmd=18,addr=0x00b913b0,size=0x00000010
+         mmcqd/0-82    [000] ...1    58.778749: mmc_blk_rw_start: cmd=18,addr=0x00b91390,size=0x00000008
+         mmcqd/0-82    [000] ..s4    58.778956: mmc_blk_rw_end: cmd=18,addr=0x00b91390,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.818682: mmc_blk_rw_start: cmd=18,addr=0x00b91438,size=0x00000008
+          <idle>-0     [000] ..s3    58.818842: mmc_blk_rw_end: cmd=18,addr=0x00b91438,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.821591: mmc_blk_rw_start: cmd=18,addr=0x00b91440,size=0x00000008
+          <idle>-0     [000] ..s3    58.821747: mmc_blk_rw_end: cmd=18,addr=0x00b91440,size=0x00000008
+         mmcqd/0-82    [000] ...1    58.821801: mmc_blk_rw_start: cmd=18,addr=0x00b91410,size=0x00000018
+          <idle>-0     [000] ..s3    58.822033: mmc_blk_rw_end: cmd=18,addr=0x00b91410,size=0x00000018
+         mmcqd/0-82    [000] ...1    58.824678: mmc_blk_rw_start: cmd=18,addr=0x00b91428,size=0x00000010
+          <idle>-0     [000] ..s3    58.824889: mmc_blk_rw_end: cmd=18,addr=0x00b91428,size=0x00000010
+         mmcqd/0-82    [000] ...1    58.824943: mmc_blk_rw_start: cmd=18,addr=0x00b91408,size=0x00000008
+          <idle>-0     [000] ..s3    58.825089: mmc_blk_rw_end: cmd=18,addr=0x00b91408,size=0x00000008
+         mmcqd/0-82    [000] ...1    59.707934: mmc_blk_rw_start: cmd=25,addr=0x00b99200,size=0x00000008
+              UI-395   [000] ..s2    59.708025: mmc_blk_rw_end: cmd=25,addr=0x00b99200,size=0x00000008
+         mmcqd/0-82    [000] ...1    59.709282: mmc_blk_rw_start: cmd=25,addr=0x002c6970,size=0x00000070
+          <idle>-0     [000] .Ns3    59.709727: mmc_blk_rw_end: cmd=25,addr=0x002c6970,size=0x00000070
+         mmcqd/0-82    [000] ...1    59.710588: mmc_blk_rw_start: cmd=25,addr=0x002c69e0,size=0x00000008
+        Binder_4-434   [000] ..s2    59.710645: mmc_blk_rw_end: cmd=25,addr=0x002c69e0,size=0x00000008
+         mmcqd/0-82    [000] ...1    59.714209: mmc_blk_rw_start: cmd=25,addr=0x00b99208,size=0x00000008
+           <...>-1541  [000] ..s2    59.714294: mmc_blk_rw_end: cmd=25,addr=0x00b99208,size=0x00000008
+         mmcqd/0-82    [000] ...1    59.721000: mmc_blk_rw_start: cmd=25,addr=0x002c69e8,size=0x00000050
+            adbd-1470  [000] ..s2    59.722370: mmc_blk_rw_end: cmd=25,addr=0x002c69e8,size=0x00000050
+         mmcqd/0-82    [000] ...1    59.725148: mmc_blk_rw_start: cmd=25,addr=0x002c6a38,size=0x00000008
+           <...>-1541  [000] .Ns3    59.725219: mmc_blk_rw_end: cmd=25,addr=0x002c6a38,size=0x00000008
+         mmcqd/0-82    [000] ...1    59.727335: mmc_blk_rw_start: cmd=25,addr=0x00b99210,size=0x00000008
+              UI-395   [000] ..s2    59.727424: mmc_blk_rw_end: cmd=25,addr=0x00b99210,size=0x00000008
+         mmcqd/0-82    [000] ...1    59.729033: mmc_blk_rw_start: cmd=25,addr=0x002c6a40,size=0x00000050
+           <...>-607   [000] ..s2    59.729377: mmc_blk_rw_end: cmd=25,addr=0x002c6a40,size=0x00000050
+         mmcqd/0-82    [000] ...1    59.731558: mmc_blk_rw_start: cmd=25,addr=0x002c6a90,size=0x00000008
+           <...>-1541  [000] ..s4    59.731617: mmc_blk_rw_end: cmd=25,addr=0x002c6a90,size=0x00000008
+         mmcqd/0-82    [000] ...1    59.792023: mmc_blk_rw_start: cmd=18,addr=0x001b9460,size=0x00000008
+        Binder_3-566   [000] ..s2    59.792250: mmc_blk_rw_end: cmd=18,addr=0x001b9460,size=0x00000008
+         mmcqd/0-82    [000] ...1    60.715097: mmc_blk_rw_start: cmd=18,addr=0x001cdd68,size=0x00000060
+          <idle>-0     [000] ..s3    60.715744: mmc_blk_rw_end: cmd=18,addr=0x001cdd68,size=0x00000060
+         mmcqd/0-82    [000] ...1    62.025279: mmc_blk_rw_start: cmd=18,addr=0x00346400,size=0x00000008
+          <idle>-0     [000] ..s4    62.025583: mmc_blk_rw_end: cmd=18,addr=0x00346400,size=0x00000008
+         mmcqd/0-82    [000] ...1    62.037473: mmc_blk_rw_start: cmd=18,addr=0x00b91460,size=0x00000010
+          <idle>-0     [000] ..s3    62.037922: mmc_blk_rw_end: cmd=18,addr=0x00b91460,size=0x00000010
+         mmcqd/0-82    [000] ...1    62.039874: mmc_blk_rw_start: cmd=18,addr=0x00347c00,size=0x00000018
+          <idle>-0     [000] ..s3    62.040414: mmc_blk_rw_end: cmd=18,addr=0x00347c00,size=0x00000018
+         mmcqd/0-82    [000] ...1    62.040972: mmc_blk_rw_start: cmd=18,addr=0x00b91470,size=0x00000010
+          <idle>-0     [000] ..s3    62.041143: mmc_blk_rw_end: cmd=18,addr=0x00b91470,size=0x00000010
+         mmcqd/0-82    [000] ...1    62.041491: mmc_blk_rw_start: cmd=18,addr=0x00b91480,size=0x00000010
+          <idle>-0     [000] ..s3    62.041660: mmc_blk_rw_end: cmd=18,addr=0x00b91480,size=0x00000010
+         mmcqd/0-82    [000] ...1    62.054430: mmc_blk_rw_start: cmd=25,addr=0x00542080,size=0x00000008
+          <idle>-0     [000] ..s3    62.054527: mmc_blk_rw_end: cmd=25,addr=0x00542080,size=0x00000008
+         mmcqd/0-82    [000] ...1    62.055112: mmc_blk_rw_start: cmd=25,addr=0x005420d0,size=0x00000010
+          <idle>-0     [000] ..s3    62.055225: mmc_blk_rw_end: cmd=25,addr=0x005420d0,size=0x00000010
+         mmcqd/0-82    [000] ...1    62.055726: mmc_blk_rw_start: cmd=25,addr=0x005420e8,size=0x00000008
+         mmcqd/0-82    [000] ..s3    62.055809: mmc_blk_rw_end: cmd=25,addr=0x005420e8,size=0x00000008
+         mmcqd/0-82    [000] ...1    62.056385: mmc_blk_rw_start: cmd=25,addr=0x00542108,size=0x00000020
+          <idle>-0     [000] .Ns3    62.056544: mmc_blk_rw_end: cmd=25,addr=0x00542108,size=0x00000020
+         mmcqd/0-82    [000] ...1    62.057231: mmc_blk_rw_start: cmd=25,addr=0x00542130,size=0x00000010
+          <idle>-0     [000] ..s3    62.057342: mmc_blk_rw_end: cmd=25,addr=0x00542130,size=0x00000010
+         mmcqd/0-82    [000] ...1    62.057850: mmc_blk_rw_start: cmd=25,addr=0x00543740,size=0x00000008
+         mmcqd/0-82    [000] ..s2    62.057929: mmc_blk_rw_end: cmd=25,addr=0x00543740,size=0x00000008
+         mmcqd/0-82    [000] ...1    62.058526: mmc_blk_rw_start: cmd=25,addr=0x00543760,size=0x00000008
+          <idle>-0     [000] ..s4    62.058609: mmc_blk_rw_end: cmd=25,addr=0x00543760,size=0x00000008
+         mmcqd/0-82    [000] ...1    62.059193: mmc_blk_rw_start: cmd=25,addr=0x005437b8,size=0x00000008
+         mmcqd/0-82    [000] ..s3    62.059274: mmc_blk_rw_end: cmd=25,addr=0x005437b8,size=0x00000008
+         mmcqd/0-82    [000] ...1    62.059876: mmc_blk_rw_start: cmd=25,addr=0x00544180,size=0x00000008
+          <idle>-0     [000] ..s4    62.059960: mmc_blk_rw_end: cmd=25,addr=0x00544180,size=0x00000008
+         mmcqd/0-82    [000] ...1    62.060559: mmc_blk_rw_start: cmd=25,addr=0x00544920,size=0x00000008
+         mmcqd/0-82    [000] ..s3    62.060638: mmc_blk_rw_end: cmd=25,addr=0x00544920,size=0x00000008
+         mmcqd/0-82    [000] ...1    62.061313: mmc_blk_rw_start: cmd=25,addr=0x00b98130,size=0x00000010
+          <idle>-0     [000] ..s3    62.061423: mmc_blk_rw_end: cmd=25,addr=0x00b98130,size=0x00000010
+         mmcqd/0-82    [000] ...1    64.790558: mmc_blk_rw_start: cmd=18,addr=0x001ae238,size=0x00000010
+          <idle>-0     [000] ..s3    64.790938: mmc_blk_rw_end: cmd=18,addr=0x001ae238,size=0x00000010
+         mmcqd/0-82    [000] ...1    64.839610: mmc_blk_rw_start: cmd=18,addr=0x0002a148,size=0x00000008
+          <idle>-0     [000] .Ns4    64.839860: mmc_blk_rw_end: cmd=18,addr=0x0002a148,size=0x00000008
+         mmcqd/0-82    [000] ...1    64.844165: mmc_blk_erase_start: cmd=3,addr=0x0002f0a8,size=0x0003af58
+         mmcqd/0-82    [000] ...1    64.855674: mmc_blk_erase_end: cmd=3,addr=0x0002f0a8,size=0x0003af58
+         mmcqd/0-82    [001] ...1    64.860452: mmc_blk_rw_start: cmd=18,addr=0x0006a148,size=0x00000008
+          <idle>-0     [000] ..s3    64.860624: mmc_blk_rw_end: cmd=18,addr=0x0006a148,size=0x00000008
+         mmcqd/0-82    [000] ...1    64.860873: mmc_blk_erase_start: cmd=3,addr=0x0006ae98,size=0x0003f168
+         mmcqd/0-82    [000] ...1    64.872976: mmc_blk_erase_end: cmd=3,addr=0x0006ae98,size=0x0003f168
+         mmcqd/0-82    [001] ...1    64.877698: mmc_blk_rw_start: cmd=18,addr=0x000aa000,size=0x00000008
+          <idle>-0     [000] ..s3    64.877871: mmc_blk_rw_end: cmd=18,addr=0x000aa000,size=0x00000008
+         mmcqd/0-82    [000] ...1    64.878114: mmc_blk_erase_start: cmd=3,addr=0x000ab010,size=0x0003eff0
+         mmcqd/0-82    [000] ...1    64.890188: mmc_blk_erase_end: cmd=3,addr=0x000ab010,size=0x0003eff0
+         mmcqd/0-82    [001] ...1    64.895271: mmc_blk_rw_start: cmd=18,addr=0x000ea148,size=0x00000008
+          <idle>-0     [000] ..s3    64.895441: mmc_blk_rw_end: cmd=18,addr=0x000ea148,size=0x00000008
+         mmcqd/0-82    [000] ...1    64.895691: mmc_blk_erase_start: cmd=3,addr=0x000eae90,size=0x0003f170
+         mmcqd/0-82    [000] ...1    64.907802: mmc_blk_erase_end: cmd=3,addr=0x000eae90,size=0x0003f170
+         mmcqd/0-82    [001] ...1    64.912733: mmc_blk_rw_start: cmd=18,addr=0x0012a000,size=0x00000008
+          <idle>-0     [000] ..s3    64.912903: mmc_blk_rw_end: cmd=18,addr=0x0012a000,size=0x00000008
+         mmcqd/0-82    [000] ...1    64.913123: mmc_blk_erase_start: cmd=3,addr=0x0012ad48,size=0x000072b8
+         mmcqd/0-82    [000] ...1    64.916366: mmc_blk_erase_end: cmd=3,addr=0x0012ad48,size=0x000072b8
+         mmcqd/0-82    [000] ...1    64.917057: mmc_blk_erase_start: cmd=3,addr=0x00308958,size=0x000006a8
+         mmcqd/0-82    [000] ...1    64.918223: mmc_blk_erase_end: cmd=3,addr=0x00308958,size=0x000006a8
+         mmcqd/0-82    [000] ...1    64.918307: mmc_blk_erase_start: cmd=3,addr=0x0030a1f0,size=0x00000610
+         mmcqd/0-82    [000] ...1    64.919345: mmc_blk_erase_end: cmd=3,addr=0x0030a1f0,size=0x00000610
+         mmcqd/0-82    [000] ...1    64.919426: mmc_blk_erase_start: cmd=3,addr=0x0030cb28,size=0x000004d8
+         mmcqd/0-82    [000] ...1    64.920372: mmc_blk_erase_end: cmd=3,addr=0x0030cb28,size=0x000004d8
+         mmcqd/0-82    [000] ...1    64.920445: mmc_blk_erase_start: cmd=3,addr=0x0030eb88,size=0x00000478
+         mmcqd/0-82    [000] ...1    64.921343: mmc_blk_erase_end: cmd=3,addr=0x0030eb88,size=0x00000478
+         mmcqd/0-82    [000] ...1    64.921414: mmc_blk_erase_start: cmd=3,addr=0x00310790,size=0x00000870
+         mmcqd/0-82    [000] ...1    64.922467: mmc_blk_erase_end: cmd=3,addr=0x00310790,size=0x00000870
+         mmcqd/0-82    [000] ...1    64.922556: mmc_blk_erase_start: cmd=3,addr=0x00311a88,size=0x00000578
+         mmcqd/0-82    [000] ...1    64.923503: mmc_blk_erase_end: cmd=3,addr=0x00311a88,size=0x00000578
+         mmcqd/0-82    [000] ...1    64.923581: mmc_blk_erase_start: cmd=3,addr=0x00317048,size=0x00002fb8
+         mmcqd/0-82    [000] ...1    64.925475: mmc_blk_erase_end: cmd=3,addr=0x00317048,size=0x00002fb8
+         mmcqd/0-82    [000] ...1    64.925765: mmc_blk_erase_start: cmd=3,addr=0x00347c18,size=0x00001108
+         mmcqd/0-82    [000] ...1    64.927235: mmc_blk_erase_end: cmd=3,addr=0x00347c18,size=0x00001108
+         mmcqd/0-82    [000] ...1    64.927364: mmc_blk_erase_start: cmd=3,addr=0x00349720,size=0x000005d0
+         mmcqd/0-82    [000] ...1    64.928362: mmc_blk_erase_end: cmd=3,addr=0x00349720,size=0x000005d0
+         mmcqd/0-82    [000] ...1    64.928439: mmc_blk_erase_start: cmd=3,addr=0x00349da0,size=0x000008b8
+         mmcqd/0-82    [000] ...1    64.930094: mmc_blk_erase_end: cmd=3,addr=0x00349da0,size=0x000008b8
+         mmcqd/0-82    [000] ...1    64.930184: mmc_blk_erase_start: cmd=3,addr=0x0034b000,size=0x00000b38
+         mmcqd/0-82    [000] ...1    64.931858: mmc_blk_erase_end: cmd=3,addr=0x0034b000,size=0x00000b38
+         mmcqd/0-82    [000] ...1    64.931961: mmc_blk_erase_start: cmd=3,addr=0x0034f000,size=0x00000c00
+         mmcqd/0-82    [000] ...1    64.933171: mmc_blk_erase_end: cmd=3,addr=0x0034f000,size=0x00000c00
+         mmcqd/0-82    [000] ...1    64.933280: mmc_blk_erase_start: cmd=3,addr=0x003510f8,size=0x00001dc0
+         mmcqd/0-82    [000] ...1    64.935361: mmc_blk_erase_end: cmd=3,addr=0x003510f8,size=0x00001dc0
+         mmcqd/0-82    [000] ...1    64.935545: mmc_blk_erase_start: cmd=3,addr=0x00352f78,size=0x00000690
+         mmcqd/0-82    [000] ...1    64.937124: mmc_blk_erase_end: cmd=3,addr=0x00352f78,size=0x00000690
+         mmcqd/0-82    [000] ...1    64.937204: mmc_blk_erase_start: cmd=3,addr=0x00357000,size=0x00001008
+         mmcqd/0-82    [000] ...1    64.938986: mmc_blk_erase_end: cmd=3,addr=0x00357000,size=0x00001008
+         mmcqd/0-82    [000] ...1    64.939146: mmc_blk_erase_start: cmd=3,addr=0x00358800,size=0x00001400
+         mmcqd/0-82    [000] ...1    64.940462: mmc_blk_erase_end: cmd=3,addr=0x00358800,size=0x00001400
+         mmcqd/0-82    [000] ...1    64.940608: mmc_blk_erase_start: cmd=3,addr=0x0035d000,size=0x00000a00
+         mmcqd/0-82    [000] ...1    64.941711: mmc_blk_erase_end: cmd=3,addr=0x0035d000,size=0x00000a00
+         mmcqd/0-82    [000] ...1    64.941808: mmc_blk_erase_start: cmd=3,addr=0x0035e528,size=0x00000ad8
+         mmcqd/0-82    [000] ...1    64.942915: mmc_blk_erase_end: cmd=3,addr=0x0035e528,size=0x00000ad8
+         mmcqd/0-82    [000] ...1    64.943014: mmc_blk_erase_start: cmd=3,addr=0x00360000,size=0x00000800
+         mmcqd/0-82    [000] ...1    64.944178: mmc_blk_erase_end: cmd=3,addr=0x00360000,size=0x00000800
+         mmcqd/0-82    [000] ...1    64.944265: mmc_blk_erase_start: cmd=3,addr=0x00360a70,size=0x00000590
+         mmcqd/0-82    [000] ...1    64.945257: mmc_blk_erase_end: cmd=3,addr=0x00360a70,size=0x00000590
+         mmcqd/0-82    [000] ...1    64.945337: mmc_blk_erase_start: cmd=3,addr=0x00361170,size=0x00008e90
+         mmcqd/0-82    [000] ...1    64.949162: mmc_blk_erase_end: cmd=3,addr=0x00361170,size=0x00008e90
+         mmcqd/0-82    [000] ...1    64.949868: mmc_blk_erase_start: cmd=3,addr=0x0036d448,size=0x00002bb8
+         mmcqd/0-82    [000] ...1    64.951650: mmc_blk_erase_end: cmd=3,addr=0x0036d448,size=0x00002bb8
+         mmcqd/0-82    [000] ...1    64.951901: mmc_blk_erase_start: cmd=3,addr=0x00372320,size=0x00000ce0
+         mmcqd/0-82    [000] ...1    64.953019: mmc_blk_erase_end: cmd=3,addr=0x00372320,size=0x00000ce0
+         mmcqd/0-82    [000] ...1    64.953130: mmc_blk_erase_start: cmd=3,addr=0x00374118,size=0x00000ee8
+         mmcqd/0-82    [000] ...1    64.954322: mmc_blk_erase_end: cmd=3,addr=0x00374118,size=0x00000ee8
+         mmcqd/0-82    [000] ...1    64.954446: mmc_blk_erase_start: cmd=3,addr=0x00375bd0,size=0x0000c430
+         mmcqd/0-82    [000] ...1    64.960104: mmc_blk_erase_end: cmd=3,addr=0x00375bd0,size=0x0000c430
+         mmcqd/0-82    [000] ...1    64.960996: mmc_blk_rw_start: cmd=18,addr=0x00383ac8,size=0x00000008
+          <idle>-0     [000] ..s3    64.961164: mmc_blk_rw_end: cmd=18,addr=0x00383ac8,size=0x00000008
+         mmcqd/0-82    [000] ...1    64.961360: mmc_blk_erase_start: cmd=3,addr=0x00384ae8,size=0x00000520
+         mmcqd/0-82    [000] ...1    64.962923: mmc_blk_erase_end: cmd=3,addr=0x00384ae8,size=0x00000520
+         mmcqd/0-82    [000] ...1    64.962990: mmc_blk_erase_start: cmd=3,addr=0x00385190,size=0x00006778
+         mmcqd/0-82    [000] ...1    64.966548: mmc_blk_erase_end: cmd=3,addr=0x00385190,size=0x00006778
+         mmcqd/0-82    [000] ...1    64.966996: mmc_blk_erase_start: cmd=3,addr=0x0038bec0,size=0x00022140
+         mmcqd/0-82    [000] ...1    64.979761: mmc_blk_erase_end: cmd=3,addr=0x0038bec0,size=0x00022140
+         mmcqd/0-82    [000] ...1    64.981889: mmc_blk_erase_start: cmd=3,addr=0x003b1808,size=0x000107f8
+         mmcqd/0-82    [000] ...1    64.988880: mmc_blk_erase_end: cmd=3,addr=0x003b1808,size=0x000107f8
+         mmcqd/0-82    [000] ...1    64.990030: mmc_blk_rw_start: cmd=18,addr=0x003c2000,size=0x00000008
+          <idle>-0     [000] ..s3    64.990196: mmc_blk_rw_end: cmd=18,addr=0x003c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    64.990399: mmc_blk_erase_start: cmd=3,addr=0x003c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.002436: mmc_blk_erase_end: cmd=3,addr=0x003c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.006530: mmc_blk_rw_start: cmd=18,addr=0x00403ac8,size=0x00000008
+          <idle>-0     [000] ..s3    65.006696: mmc_blk_rw_end: cmd=18,addr=0x00403ac8,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.006904: mmc_blk_erase_start: cmd=3,addr=0x00404ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    65.018401: mmc_blk_erase_end: cmd=3,addr=0x00404ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    65.022323: mmc_blk_rw_start: cmd=18,addr=0x00442000,size=0x00000008
+          <idle>-0     [000] ..s3    65.022490: mmc_blk_rw_end: cmd=18,addr=0x00442000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.022695: mmc_blk_erase_start: cmd=3,addr=0x00443000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    65.034731: mmc_blk_erase_end: cmd=3,addr=0x00443000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    65.038992: mmc_blk_rw_start: cmd=18,addr=0x00483ac8,size=0x00000008
+          <idle>-0     [000] ..s3    65.039163: mmc_blk_rw_end: cmd=18,addr=0x00483ac8,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.039441: mmc_blk_erase_start: cmd=3,addr=0x00484ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    65.051022: mmc_blk_erase_end: cmd=3,addr=0x00484ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    65.054504: mmc_blk_rw_start: cmd=18,addr=0x004c2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.054666: mmc_blk_rw_end: cmd=18,addr=0x004c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.054850: mmc_blk_erase_start: cmd=3,addr=0x004c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.066849: mmc_blk_erase_end: cmd=3,addr=0x004c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.070240: mmc_blk_rw_start: cmd=18,addr=0x00503ac8,size=0x00000008
+          <idle>-0     [000] ..s3    65.070402: mmc_blk_rw_end: cmd=18,addr=0x00503ac8,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.070586: mmc_blk_erase_start: cmd=3,addr=0x00504ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    65.082108: mmc_blk_erase_end: cmd=3,addr=0x00504ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    65.085540: mmc_blk_rw_start: cmd=18,addr=0x00542000,size=0x00000008
+          <idle>-0     [000] ..s3    65.085704: mmc_blk_rw_end: cmd=18,addr=0x00542000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.085878: mmc_blk_erase_start: cmd=3,addr=0x00546158,size=0x00001360
+         mmcqd/0-82    [000] ...1    65.087692: mmc_blk_erase_end: cmd=3,addr=0x00546158,size=0x00001360
+         mmcqd/0-82    [000] ...1    65.087792: mmc_blk_erase_start: cmd=3,addr=0x005477b0,size=0x00000950
+         mmcqd/0-82    [000] ...1    65.088834: mmc_blk_erase_end: cmd=3,addr=0x005477b0,size=0x00000950
+         mmcqd/0-82    [000] ...1    65.088915: mmc_blk_erase_start: cmd=3,addr=0x00548268,size=0x00039d98
+         mmcqd/0-82    [000] ...1    65.099331: mmc_blk_erase_end: cmd=3,addr=0x00548268,size=0x00039d98
+         mmcqd/0-82    [000] ...1    65.102484: mmc_blk_rw_start: cmd=18,addr=0x00582000,size=0x00000008
+          <idle>-0     [000] ..s3    65.102697: mmc_blk_rw_end: cmd=18,addr=0x00582000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.102950: mmc_blk_erase_start: cmd=3,addr=0x00584008,size=0x00000ff8
+         mmcqd/0-82    [000] ...1    65.104144: mmc_blk_erase_end: cmd=3,addr=0x00584008,size=0x00000ff8
+         mmcqd/0-82    [000] ...1    65.104234: mmc_blk_erase_start: cmd=3,addr=0x005856b8,size=0x00000948
+         mmcqd/0-82    [000] ...1    65.105273: mmc_blk_erase_end: cmd=3,addr=0x005856b8,size=0x00000948
+         mmcqd/0-82    [000] ...1    65.105341: mmc_blk_erase_start: cmd=3,addr=0x005866c0,size=0x00000e30
+         mmcqd/0-82    [000] ...1    65.106438: mmc_blk_erase_end: cmd=3,addr=0x005866c0,size=0x00000e30
+         mmcqd/0-82    [000] ...1    65.106524: mmc_blk_erase_start: cmd=3,addr=0x00587508,size=0x00000800
+         mmcqd/0-82    [000] ...1    65.108103: mmc_blk_erase_end: cmd=3,addr=0x00587508,size=0x00000800
+         mmcqd/0-82    [000] ...1    65.108179: mmc_blk_erase_start: cmd=3,addr=0x00587d68,size=0x0003a298
+         mmcqd/0-82    [000] ...1    65.118631: mmc_blk_erase_end: cmd=3,addr=0x00587d68,size=0x0003a298
+         mmcqd/0-82    [000] ...1    65.121820: mmc_blk_rw_start: cmd=18,addr=0x005c2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.121982: mmc_blk_rw_end: cmd=18,addr=0x005c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.122166: mmc_blk_erase_start: cmd=3,addr=0x005c3000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    65.134174: mmc_blk_erase_end: cmd=3,addr=0x005c3000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    65.137513: mmc_blk_rw_start: cmd=18,addr=0x00602000,size=0x00000008
+          <idle>-0     [000] ..s3    65.137675: mmc_blk_rw_end: cmd=18,addr=0x00602000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.137858: mmc_blk_erase_start: cmd=3,addr=0x00602ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.149874: mmc_blk_erase_end: cmd=3,addr=0x00602ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.153212: mmc_blk_rw_start: cmd=18,addr=0x00642000,size=0x00000008
+          <idle>-0     [000] ..s3    65.153374: mmc_blk_rw_end: cmd=18,addr=0x00642000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.153556: mmc_blk_erase_start: cmd=3,addr=0x00642ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.165578: mmc_blk_erase_end: cmd=3,addr=0x00642ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.169139: mmc_blk_rw_start: cmd=18,addr=0x00682000,size=0x00000008
+          <idle>-0     [000] ..s3    65.169302: mmc_blk_rw_end: cmd=18,addr=0x00682000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.169483: mmc_blk_erase_start: cmd=3,addr=0x00682ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.181507: mmc_blk_erase_end: cmd=3,addr=0x00682ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.185105: mmc_blk_rw_start: cmd=18,addr=0x006c2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.185267: mmc_blk_rw_end: cmd=18,addr=0x006c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.185450: mmc_blk_erase_start: cmd=3,addr=0x006c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.204743: mmc_blk_erase_end: cmd=3,addr=0x006c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.208326: mmc_blk_rw_start: cmd=18,addr=0x00702000,size=0x00000008
+          <idle>-0     [000] ..s3    65.208489: mmc_blk_rw_end: cmd=18,addr=0x00702000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.208671: mmc_blk_erase_start: cmd=3,addr=0x00703180,size=0x0003ee80
+         mmcqd/0-82    [000] ...1    65.220673: mmc_blk_erase_end: cmd=3,addr=0x00703180,size=0x0003ee80
+         mmcqd/0-82    [000] ...1    65.224277: mmc_blk_rw_start: cmd=18,addr=0x00742000,size=0x00000008
+          <idle>-0     [000] ..s3    65.224440: mmc_blk_rw_end: cmd=18,addr=0x00742000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.224623: mmc_blk_erase_start: cmd=3,addr=0x00743098,size=0x0003ef68
+         mmcqd/0-82    [000] ...1    65.236666: mmc_blk_erase_end: cmd=3,addr=0x00743098,size=0x0003ef68
+         mmcqd/0-82    [000] ...1    65.240177: mmc_blk_rw_start: cmd=18,addr=0x00782000,size=0x00000008
+          <idle>-0     [000] ..s3    65.240340: mmc_blk_rw_end: cmd=18,addr=0x00782000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.240521: mmc_blk_erase_start: cmd=3,addr=0x00783000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    65.252559: mmc_blk_erase_end: cmd=3,addr=0x00783000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    65.256080: mmc_blk_rw_start: cmd=18,addr=0x007c2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.256241: mmc_blk_rw_end: cmd=18,addr=0x007c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.256423: mmc_blk_erase_start: cmd=3,addr=0x007c30d0,size=0x0003ef30
+         mmcqd/0-82    [000] ...1    65.268445: mmc_blk_erase_end: cmd=3,addr=0x007c30d0,size=0x0003ef30
+         mmcqd/0-82    [000] ...1    65.271804: mmc_blk_rw_start: cmd=18,addr=0x00802000,size=0x00000008
+          <idle>-0     [000] ..s3    65.271968: mmc_blk_rw_end: cmd=18,addr=0x00802000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.272151: mmc_blk_erase_start: cmd=3,addr=0x00803010,size=0x0003eff0
+         mmcqd/0-82    [000] ...1    65.284198: mmc_blk_erase_end: cmd=3,addr=0x00803010,size=0x0003eff0
+         mmcqd/0-82    [000] ...1    65.287616: mmc_blk_rw_start: cmd=18,addr=0x00842000,size=0x00000008
+          <idle>-0     [000] ..s3    65.287778: mmc_blk_rw_end: cmd=18,addr=0x00842000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.287959: mmc_blk_erase_start: cmd=3,addr=0x00842ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.299984: mmc_blk_erase_end: cmd=3,addr=0x00842ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.303613: mmc_blk_rw_start: cmd=18,addr=0x00882000,size=0x00000008
+          <idle>-0     [000] ..s3    65.303775: mmc_blk_rw_end: cmd=18,addr=0x00882000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.303957: mmc_blk_erase_start: cmd=3,addr=0x00882ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.316036: mmc_blk_erase_end: cmd=3,addr=0x00882ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.319544: mmc_blk_rw_start: cmd=18,addr=0x008c2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.319756: mmc_blk_rw_end: cmd=18,addr=0x008c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.320008: mmc_blk_erase_start: cmd=3,addr=0x008c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.332066: mmc_blk_erase_end: cmd=3,addr=0x008c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.335494: mmc_blk_rw_start: cmd=18,addr=0x00903ac8,size=0x00000008
+          <idle>-0     [000] ..s3    65.335656: mmc_blk_rw_end: cmd=18,addr=0x00903ac8,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.335841: mmc_blk_erase_start: cmd=3,addr=0x00904ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    65.347297: mmc_blk_erase_end: cmd=3,addr=0x00904ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    65.350772: mmc_blk_rw_start: cmd=18,addr=0x00942000,size=0x00000008
+          <idle>-0     [000] ..s3    65.350934: mmc_blk_rw_end: cmd=18,addr=0x00942000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.351115: mmc_blk_erase_start: cmd=3,addr=0x00942ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.363095: mmc_blk_erase_end: cmd=3,addr=0x00942ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.366656: mmc_blk_rw_start: cmd=18,addr=0x00983ac8,size=0x00000008
+          <idle>-0     [000] ..s3    65.366818: mmc_blk_rw_end: cmd=18,addr=0x00983ac8,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.366999: mmc_blk_erase_start: cmd=3,addr=0x00984ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    65.378413: mmc_blk_erase_end: cmd=3,addr=0x00984ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    65.381966: mmc_blk_rw_start: cmd=18,addr=0x009c2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.382127: mmc_blk_rw_end: cmd=18,addr=0x009c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.382310: mmc_blk_erase_start: cmd=3,addr=0x009c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.394379: mmc_blk_erase_end: cmd=3,addr=0x009c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.397815: mmc_blk_rw_start: cmd=18,addr=0x00a02000,size=0x00000008
+          <idle>-0     [000] ..s3    65.397978: mmc_blk_rw_end: cmd=18,addr=0x00a02000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.398162: mmc_blk_erase_start: cmd=3,addr=0x00a02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.410211: mmc_blk_erase_end: cmd=3,addr=0x00a02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.413546: mmc_blk_rw_start: cmd=18,addr=0x00a42000,size=0x00000008
+          <idle>-0     [000] ..s3    65.413708: mmc_blk_rw_end: cmd=18,addr=0x00a42000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.413888: mmc_blk_erase_start: cmd=3,addr=0x00a42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.425781: mmc_blk_erase_end: cmd=3,addr=0x00a42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.429337: mmc_blk_rw_start: cmd=18,addr=0x00a82000,size=0x00000008
+          <idle>-0     [000] ..s3    65.429499: mmc_blk_rw_end: cmd=18,addr=0x00a82000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.429680: mmc_blk_erase_start: cmd=3,addr=0x00a82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.441736: mmc_blk_erase_end: cmd=3,addr=0x00a82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.445303: mmc_blk_rw_start: cmd=18,addr=0x00ac2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.445465: mmc_blk_rw_end: cmd=18,addr=0x00ac2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.445648: mmc_blk_erase_start: cmd=3,addr=0x00ac2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.457715: mmc_blk_erase_end: cmd=3,addr=0x00ac2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.461193: mmc_blk_rw_start: cmd=18,addr=0x00b02000,size=0x00000008
+          <idle>-0     [000] ..s3    65.461405: mmc_blk_rw_end: cmd=18,addr=0x00b02000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.461664: mmc_blk_erase_start: cmd=3,addr=0x00b02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.473758: mmc_blk_erase_end: cmd=3,addr=0x00b02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.477284: mmc_blk_erase_start: cmd=3,addr=0x00b43010,size=0x0003eff0
+         mmcqd/0-82    [000] ...1    65.489346: mmc_blk_erase_end: cmd=3,addr=0x00b43010,size=0x0003eff0
+         mmcqd/0-82    [000] ...1    65.492611: mmc_blk_erase_start: cmd=3,addr=0x00b83100,size=0x00000f00
+         mmcqd/0-82    [000] ...1    65.493769: mmc_blk_erase_end: cmd=3,addr=0x00b83100,size=0x00000f00
+         mmcqd/0-82    [000] ...1    65.493857: mmc_blk_erase_start: cmd=3,addr=0x00b85c30,size=0x00000480
+         mmcqd/0-82    [000] ...1    65.494702: mmc_blk_erase_end: cmd=3,addr=0x00b85c30,size=0x00000480
+         mmcqd/0-82    [000] ...1    65.494754: mmc_blk_erase_start: cmd=3,addr=0x00b86160,size=0x00000fa0
+         mmcqd/0-82    [000] ...1    65.495904: mmc_blk_erase_end: cmd=3,addr=0x00b86160,size=0x00000fa0
+         mmcqd/0-82    [000] ...1    65.495991: mmc_blk_erase_start: cmd=3,addr=0x00b872a8,size=0x00000e00
+         mmcqd/0-82    [000] ...1    65.497626: mmc_blk_erase_end: cmd=3,addr=0x00b872a8,size=0x00000e00
+         mmcqd/0-82    [000] ...1    65.497708: mmc_blk_erase_start: cmd=3,addr=0x00b88278,size=0x00001078
+         mmcqd/0-82    [000] ...1    65.498870: mmc_blk_erase_end: cmd=3,addr=0x00b88278,size=0x00001078
+         mmcqd/0-82    [000] ...1    65.498961: mmc_blk_erase_start: cmd=3,addr=0x00b89320,size=0x000016e8
+         mmcqd/0-82    [000] ...1    65.500863: mmc_blk_erase_end: cmd=3,addr=0x00b89320,size=0x000016e8
+         mmcqd/0-82    [000] ...1    65.500975: mmc_blk_erase_start: cmd=3,addr=0x00b8aa28,size=0x00000660
+         mmcqd/0-82    [000] ...1    65.502494: mmc_blk_erase_end: cmd=3,addr=0x00b8aa28,size=0x00000660
+         mmcqd/0-82    [000] ...1    65.502552: mmc_blk_erase_start: cmd=3,addr=0x00b8b108,size=0x00000f60
+         mmcqd/0-82    [000] ...1    65.504262: mmc_blk_erase_end: cmd=3,addr=0x00b8b108,size=0x00000f60
+         mmcqd/0-82    [000] ...1    65.504350: mmc_blk_erase_start: cmd=3,addr=0x00b8c138,size=0x00000f88
+         mmcqd/0-82    [000] ...1    65.505501: mmc_blk_erase_end: cmd=3,addr=0x00b8c138,size=0x00000f88
+         mmcqd/0-82    [000] ...1    65.505588: mmc_blk_erase_start: cmd=3,addr=0x00b8d0e0,size=0x00000fd0
+         mmcqd/0-82    [000] ...1    65.506685: mmc_blk_erase_end: cmd=3,addr=0x00b8d0e0,size=0x00000fd0
+         mmcqd/0-82    [000] ...1    65.506776: mmc_blk_erase_start: cmd=3,addr=0x00b8e0f8,size=0x00000f70
+         mmcqd/0-82    [000] ...1    65.508408: mmc_blk_erase_end: cmd=3,addr=0x00b8e0f8,size=0x00000f70
+         mmcqd/0-82    [000] ...1    65.508496: mmc_blk_erase_start: cmd=3,addr=0x00b8f070,size=0x00001770
+         mmcqd/0-82    [000] ...1    65.509835: mmc_blk_erase_end: cmd=3,addr=0x00b8f070,size=0x00001770
+         mmcqd/0-82    [000] ...1    65.509946: mmc_blk_erase_start: cmd=3,addr=0x00b907f0,size=0x00000870
+         mmcqd/0-82    [000] ...1    65.510983: mmc_blk_erase_end: cmd=3,addr=0x00b907f0,size=0x00000870
+         mmcqd/0-82    [000] ...1    65.511048: mmc_blk_erase_start: cmd=3,addr=0x00b914c0,size=0x00000d28
+         mmcqd/0-82    [000] ...1    65.512622: mmc_blk_erase_end: cmd=3,addr=0x00b914c0,size=0x00000d28
+         mmcqd/0-82    [000] ...1    65.512701: mmc_blk_erase_start: cmd=3,addr=0x00b921f0,size=0x00000e88
+         mmcqd/0-82    [000] ...1    65.514392: mmc_blk_erase_end: cmd=3,addr=0x00b921f0,size=0x00000e88
+         mmcqd/0-82    [000] ...1    65.514482: mmc_blk_erase_start: cmd=3,addr=0x00b930d0,size=0x00000fd8
+         mmcqd/0-82    [000] ...1    65.516232: mmc_blk_erase_end: cmd=3,addr=0x00b930d0,size=0x00000fd8
+         mmcqd/0-82    [000] ...1    65.516320: mmc_blk_erase_start: cmd=3,addr=0x00b940e0,size=0x00001048
+         mmcqd/0-82    [000] ...1    65.518068: mmc_blk_erase_end: cmd=3,addr=0x00b940e0,size=0x00001048
+         mmcqd/0-82    [000] ...1    65.518158: mmc_blk_erase_start: cmd=3,addr=0x00b95130,size=0x00000fa8
+         mmcqd/0-82    [000] ...1    65.519867: mmc_blk_erase_end: cmd=3,addr=0x00b95130,size=0x00000fa8
+         mmcqd/0-82    [000] ...1    65.519954: mmc_blk_erase_start: cmd=3,addr=0x00b962e0,size=0x000004b8
+         mmcqd/0-82    [000] ...1    65.521465: mmc_blk_erase_end: cmd=3,addr=0x00b962e0,size=0x000004b8
+         mmcqd/0-82    [000] ...1    65.521517: mmc_blk_erase_start: cmd=3,addr=0x00b96840,size=0x000008f0
+         mmcqd/0-82    [000] ...1    65.522552: mmc_blk_erase_end: cmd=3,addr=0x00b96840,size=0x000008f0
+         mmcqd/0-82    [000] ...1    65.522618: mmc_blk_erase_start: cmd=3,addr=0x00b97458,size=0x00000ba8
+         mmcqd/0-82    [000] ...1    65.523659: mmc_blk_erase_end: cmd=3,addr=0x00b97458,size=0x00000ba8
+         mmcqd/0-82    [000] ...1    65.523745: mmc_blk_erase_start: cmd=3,addr=0x00b9a000,size=0x00028000
+         mmcqd/0-82    [000] ...1    65.528268: mmc_blk_erase_end: cmd=3,addr=0x00b9a000,size=0x00028000
+         mmcqd/0-82    [000] ...1    65.530508: mmc_blk_rw_start: cmd=18,addr=0x00bc2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.530669: mmc_blk_rw_end: cmd=18,addr=0x00bc2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.530852: mmc_blk_erase_start: cmd=3,addr=0x00bc2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.542925: mmc_blk_erase_end: cmd=3,addr=0x00bc2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.546510: mmc_blk_rw_start: cmd=18,addr=0x00c02000,size=0x00000008
+          <idle>-0     [000] ..s3    65.546673: mmc_blk_rw_end: cmd=18,addr=0x00c02000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.546729: mmc_blk_rw_start: cmd=25,addr=0x002c6a98,size=0x00000058
+          <idle>-0     [000] ..s3    65.547168: mmc_blk_rw_end: cmd=25,addr=0x002c6a98,size=0x00000058
+         mmcqd/0-82    [000] ...1    65.547855: mmc_blk_rw_start: cmd=25,addr=0x002c6af0,size=0x00000008
+          <idle>-0     [000] ..s3    65.547938: mmc_blk_rw_end: cmd=25,addr=0x002c6af0,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.548643: mmc_blk_erase_start: cmd=3,addr=0x00c02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.560697: mmc_blk_erase_end: cmd=3,addr=0x00c02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.564290: mmc_blk_rw_start: cmd=18,addr=0x00c42000,size=0x00000008
+          <idle>-0     [000] ..s3    65.564452: mmc_blk_rw_end: cmd=18,addr=0x00c42000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.564635: mmc_blk_erase_start: cmd=3,addr=0x00c42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.576689: mmc_blk_erase_end: cmd=3,addr=0x00c42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.580050: mmc_blk_rw_start: cmd=18,addr=0x00c82000,size=0x00000008
+          <idle>-0     [000] ..s3    65.580211: mmc_blk_rw_end: cmd=18,addr=0x00c82000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.580392: mmc_blk_erase_start: cmd=3,addr=0x00c82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.593009: mmc_blk_erase_end: cmd=3,addr=0x00c82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.596373: mmc_blk_rw_start: cmd=18,addr=0x00cc2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.596537: mmc_blk_rw_end: cmd=18,addr=0x00cc2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.596719: mmc_blk_erase_start: cmd=3,addr=0x00cc3000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    65.609463: mmc_blk_erase_end: cmd=3,addr=0x00cc3000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    65.612802: mmc_blk_rw_start: cmd=18,addr=0x00d02000,size=0x00000008
+          <idle>-0     [000] ..s3    65.612963: mmc_blk_rw_end: cmd=18,addr=0x00d02000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.613147: mmc_blk_erase_start: cmd=3,addr=0x00d02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.625991: mmc_blk_erase_end: cmd=3,addr=0x00d02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.629539: mmc_blk_rw_start: cmd=18,addr=0x00d42000,size=0x00000008
+          <idle>-0     [000] ..s3    65.629700: mmc_blk_rw_end: cmd=18,addr=0x00d42000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.629879: mmc_blk_erase_start: cmd=3,addr=0x00d42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.642728: mmc_blk_erase_end: cmd=3,addr=0x00d42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.646085: mmc_blk_rw_start: cmd=18,addr=0x00d82000,size=0x00000008
+          <idle>-0     [000] ..s3    65.646246: mmc_blk_rw_end: cmd=18,addr=0x00d82000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.646428: mmc_blk_erase_start: cmd=3,addr=0x00d82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.659272: mmc_blk_erase_end: cmd=3,addr=0x00d82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.662916: mmc_blk_rw_start: cmd=18,addr=0x00dc2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.663083: mmc_blk_rw_end: cmd=18,addr=0x00dc2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.663297: mmc_blk_erase_start: cmd=3,addr=0x00dc2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.676145: mmc_blk_erase_end: cmd=3,addr=0x00dc2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.679765: mmc_blk_rw_start: cmd=18,addr=0x00e02000,size=0x00000008
+          <idle>-0     [000] ..s3    65.679928: mmc_blk_rw_end: cmd=18,addr=0x00e02000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.680119: mmc_blk_erase_start: cmd=3,addr=0x00e02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.692956: mmc_blk_erase_end: cmd=3,addr=0x00e02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.696314: mmc_blk_rw_start: cmd=18,addr=0x00e42000,size=0x00000008
+          <idle>-0     [000] ..s3    65.696476: mmc_blk_rw_end: cmd=18,addr=0x00e42000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.696658: mmc_blk_erase_start: cmd=3,addr=0x00e42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.709458: mmc_blk_erase_end: cmd=3,addr=0x00e42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.712997: mmc_blk_rw_start: cmd=18,addr=0x00e82000,size=0x00000008
+          <idle>-0     [000] ..s3    65.713159: mmc_blk_rw_end: cmd=18,addr=0x00e82000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.713339: mmc_blk_erase_start: cmd=3,addr=0x00e82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.726167: mmc_blk_erase_end: cmd=3,addr=0x00e82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.729808: mmc_blk_rw_start: cmd=18,addr=0x00ec2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.729969: mmc_blk_rw_end: cmd=18,addr=0x00ec2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.730151: mmc_blk_erase_start: cmd=3,addr=0x00ec2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.742962: mmc_blk_erase_end: cmd=3,addr=0x00ec2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.746523: mmc_blk_rw_start: cmd=18,addr=0x00f03ac8,size=0x00000008
+          <idle>-0     [000] ..s3    65.746736: mmc_blk_rw_end: cmd=18,addr=0x00f03ac8,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.746997: mmc_blk_erase_start: cmd=3,addr=0x00f04ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    65.759333: mmc_blk_erase_end: cmd=3,addr=0x00f04ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    65.762585: mmc_blk_rw_start: cmd=18,addr=0x00f42000,size=0x00000008
+          <idle>-0     [000] ..s3    65.762746: mmc_blk_rw_end: cmd=18,addr=0x00f42000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.762928: mmc_blk_erase_start: cmd=3,addr=0x00f42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.775775: mmc_blk_erase_end: cmd=3,addr=0x00f42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.779190: mmc_blk_rw_start: cmd=18,addr=0x00f82000,size=0x00000008
+          <idle>-0     [000] ..s3    65.779354: mmc_blk_rw_end: cmd=18,addr=0x00f82000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.779536: mmc_blk_erase_start: cmd=3,addr=0x00f83008,size=0x0003eff8
+         mmcqd/0-82    [000] ...1    65.792334: mmc_blk_erase_end: cmd=3,addr=0x00f83008,size=0x0003eff8
+         mmcqd/0-82    [000] ...1    65.795718: mmc_blk_rw_start: cmd=18,addr=0x00fc2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.795880: mmc_blk_rw_end: cmd=18,addr=0x00fc2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.796061: mmc_blk_erase_start: cmd=3,addr=0x00fc3010,size=0x0003eff0
+         mmcqd/0-82    [000] ...1    65.808910: mmc_blk_erase_end: cmd=3,addr=0x00fc3010,size=0x0003eff0
+         mmcqd/0-82    [000] ...1    65.812397: mmc_blk_rw_start: cmd=18,addr=0x01002000,size=0x00000008
+          <idle>-0     [000] ..s3    65.812559: mmc_blk_rw_end: cmd=18,addr=0x01002000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.812741: mmc_blk_erase_start: cmd=3,addr=0x01002ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.825541: mmc_blk_erase_end: cmd=3,addr=0x01002ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.828878: mmc_blk_rw_start: cmd=18,addr=0x01042000,size=0x00000008
+          <idle>-0     [000] ..s3    65.829040: mmc_blk_rw_end: cmd=18,addr=0x01042000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.829243: mmc_blk_erase_start: cmd=3,addr=0x01042ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.848483: mmc_blk_erase_end: cmd=3,addr=0x01042ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.852064: mmc_blk_rw_start: cmd=18,addr=0x01082000,size=0x00000008
+          <idle>-0     [000] ..s3    65.852225: mmc_blk_rw_end: cmd=18,addr=0x01082000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.852405: mmc_blk_erase_start: cmd=3,addr=0x01082ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.865241: mmc_blk_erase_end: cmd=3,addr=0x01082ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.868741: mmc_blk_rw_start: cmd=18,addr=0x010c2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.868903: mmc_blk_rw_end: cmd=18,addr=0x010c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.869104: mmc_blk_erase_start: cmd=3,addr=0x010c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.881967: mmc_blk_erase_end: cmd=3,addr=0x010c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.885518: mmc_blk_rw_start: cmd=18,addr=0x01102000,size=0x00000008
+          <idle>-0     [000] ..s3    65.885679: mmc_blk_rw_end: cmd=18,addr=0x01102000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.885861: mmc_blk_erase_start: cmd=3,addr=0x01102ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.898719: mmc_blk_erase_end: cmd=3,addr=0x01102ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.902088: mmc_blk_rw_start: cmd=18,addr=0x01142000,size=0x00000008
+          <idle>-0     [000] ..s3    65.902250: mmc_blk_rw_end: cmd=18,addr=0x01142000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.902431: mmc_blk_erase_start: cmd=3,addr=0x01142ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.915275: mmc_blk_erase_end: cmd=3,addr=0x01142ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.918619: mmc_blk_rw_start: cmd=18,addr=0x01182000,size=0x00000008
+          <idle>-0     [000] ..s3    65.918781: mmc_blk_rw_end: cmd=18,addr=0x01182000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.918963: mmc_blk_erase_start: cmd=3,addr=0x01182ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.931861: mmc_blk_erase_end: cmd=3,addr=0x01182ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.935374: mmc_blk_rw_start: cmd=18,addr=0x011c2000,size=0x00000008
+          <idle>-0     [000] ..s3    65.935536: mmc_blk_rw_end: cmd=18,addr=0x011c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.935718: mmc_blk_erase_start: cmd=3,addr=0x011c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.948584: mmc_blk_erase_end: cmd=3,addr=0x011c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.952113: mmc_blk_rw_start: cmd=18,addr=0x01202000,size=0x00000008
+          <idle>-0     [000] ..s3    65.952275: mmc_blk_rw_end: cmd=18,addr=0x01202000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.952457: mmc_blk_erase_start: cmd=3,addr=0x01202ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.965256: mmc_blk_erase_end: cmd=3,addr=0x01202ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.968807: mmc_blk_rw_start: cmd=18,addr=0x01242000,size=0x00000008
+          <idle>-0     [000] ..s3    65.968969: mmc_blk_rw_end: cmd=18,addr=0x01242000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.969174: mmc_blk_erase_start: cmd=3,addr=0x01242ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.982055: mmc_blk_erase_end: cmd=3,addr=0x01242ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.985654: mmc_blk_rw_start: cmd=18,addr=0x01282000,size=0x00000008
+          <idle>-0     [000] ..s3    65.985816: mmc_blk_rw_end: cmd=18,addr=0x01282000,size=0x00000008
+         mmcqd/0-82    [000] ...1    65.985994: mmc_blk_erase_start: cmd=3,addr=0x01282ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    65.998829: mmc_blk_erase_end: cmd=3,addr=0x01282ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.002211: mmc_blk_rw_start: cmd=18,addr=0x012c2000,size=0x00000008
+          <idle>-0     [000] ..s3    66.002372: mmc_blk_rw_end: cmd=18,addr=0x012c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.002549: mmc_blk_erase_start: cmd=3,addr=0x012c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.015395: mmc_blk_erase_end: cmd=3,addr=0x012c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.018738: mmc_blk_rw_start: cmd=18,addr=0x01302000,size=0x00000008
+          <idle>-0     [000] ..s3    66.018899: mmc_blk_rw_end: cmd=18,addr=0x01302000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.019109: mmc_blk_erase_start: cmd=3,addr=0x01302ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.031822: mmc_blk_erase_end: cmd=3,addr=0x01302ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.035182: mmc_blk_rw_start: cmd=18,addr=0x01342000,size=0x00000008
+          <idle>-0     [000] ..s3    66.035344: mmc_blk_rw_end: cmd=18,addr=0x01342000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.035526: mmc_blk_erase_start: cmd=3,addr=0x01342ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.048386: mmc_blk_erase_end: cmd=3,addr=0x01342ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.051777: mmc_blk_rw_start: cmd=18,addr=0x01382000,size=0x00000008
+          <idle>-0     [000] ..s3    66.051938: mmc_blk_rw_end: cmd=18,addr=0x01382000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.052119: mmc_blk_erase_start: cmd=3,addr=0x01382ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.064933: mmc_blk_erase_end: cmd=3,addr=0x01382ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.068266: mmc_blk_rw_start: cmd=18,addr=0x013c2000,size=0x00000008
+          <idle>-0     [000] ..s3    66.068428: mmc_blk_rw_end: cmd=18,addr=0x013c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.068610: mmc_blk_erase_start: cmd=3,addr=0x013c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.081409: mmc_blk_erase_end: cmd=3,addr=0x013c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.084838: mmc_blk_rw_start: cmd=18,addr=0x01402000,size=0x00000008
+          <idle>-0     [000] ..s3    66.085004: mmc_blk_rw_end: cmd=18,addr=0x01402000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.085192: mmc_blk_erase_start: cmd=3,addr=0x01403000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    66.097986: mmc_blk_erase_end: cmd=3,addr=0x01403000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    66.101443: mmc_blk_rw_start: cmd=18,addr=0x01442000,size=0x00000008
+          <idle>-0     [000] ..s3    66.101605: mmc_blk_rw_end: cmd=18,addr=0x01442000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.101787: mmc_blk_erase_start: cmd=3,addr=0x01442ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.114633: mmc_blk_erase_end: cmd=3,addr=0x01442ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.118042: mmc_blk_rw_start: cmd=18,addr=0x01482000,size=0x00000008
+          <idle>-0     [000] ..s3    66.118204: mmc_blk_rw_end: cmd=18,addr=0x01482000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.118386: mmc_blk_erase_start: cmd=3,addr=0x01482ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.131232: mmc_blk_erase_end: cmd=3,addr=0x01482ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.134684: mmc_blk_rw_start: cmd=18,addr=0x014c2000,size=0x00000008
+          <idle>-0     [000] ..s3    66.134845: mmc_blk_rw_end: cmd=18,addr=0x014c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.135026: mmc_blk_erase_start: cmd=3,addr=0x014c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.147837: mmc_blk_erase_end: cmd=3,addr=0x014c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.151424: mmc_blk_rw_start: cmd=18,addr=0x01502000,size=0x00000008
+          <idle>-0     [000] ..s3    66.151586: mmc_blk_rw_end: cmd=18,addr=0x01502000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.151768: mmc_blk_erase_start: cmd=3,addr=0x01502ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.164628: mmc_blk_erase_end: cmd=3,addr=0x01502ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.167964: mmc_blk_rw_start: cmd=18,addr=0x01542000,size=0x00000008
+          <idle>-0     [000] ..s3    66.168125: mmc_blk_rw_end: cmd=18,addr=0x01542000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.168300: mmc_blk_erase_start: cmd=3,addr=0x01542ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.181084: mmc_blk_erase_end: cmd=3,addr=0x01542ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.184504: mmc_blk_rw_start: cmd=18,addr=0x01582000,size=0x00000008
+          <idle>-0     [000] ..s3    66.184666: mmc_blk_rw_end: cmd=18,addr=0x01582000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.184837: mmc_blk_erase_start: cmd=3,addr=0x01582ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.197739: mmc_blk_erase_end: cmd=3,addr=0x01582ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.201126: mmc_blk_erase_start: cmd=3,addr=0x015c3008,size=0x0003eff8
+         mmcqd/0-82    [000] ...1    66.213978: mmc_blk_erase_end: cmd=3,addr=0x015c3008,size=0x0003eff8
+         mmcqd/0-82    [000] ...1    66.217400: mmc_blk_rw_start: cmd=18,addr=0x01602000,size=0x00000008
+          <idle>-0     [000] ..s3    66.217565: mmc_blk_rw_end: cmd=18,addr=0x01602000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.217746: mmc_blk_erase_start: cmd=3,addr=0x01603000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    66.230570: mmc_blk_erase_end: cmd=3,addr=0x01603000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    66.233942: mmc_blk_rw_start: cmd=18,addr=0x01642000,size=0x00000008
+          <idle>-0     [000] ..s3    66.234107: mmc_blk_rw_end: cmd=18,addr=0x01642000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.234290: mmc_blk_erase_start: cmd=3,addr=0x01642ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.247107: mmc_blk_erase_end: cmd=3,addr=0x01642ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.250616: mmc_blk_rw_start: cmd=18,addr=0x01682000,size=0x00000008
+          <idle>-0     [000] ..s3    66.250778: mmc_blk_rw_end: cmd=18,addr=0x01682000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.250962: mmc_blk_erase_start: cmd=3,addr=0x01682ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.263787: mmc_blk_erase_end: cmd=3,addr=0x01682ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.267219: mmc_blk_rw_start: cmd=18,addr=0x016c2000,size=0x00000008
+          <idle>-0     [000] ..s3    66.267380: mmc_blk_rw_end: cmd=18,addr=0x016c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.267561: mmc_blk_erase_start: cmd=3,addr=0x016c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.280363: mmc_blk_erase_end: cmd=3,addr=0x016c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.283772: mmc_blk_rw_start: cmd=18,addr=0x01703ac8,size=0x00000008
+          <idle>-0     [000] ..s3    66.283934: mmc_blk_rw_end: cmd=18,addr=0x01703ac8,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.284146: mmc_blk_erase_start: cmd=3,addr=0x01704ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    66.296455: mmc_blk_erase_end: cmd=3,addr=0x01704ac0,size=0x0003d540
+         mmcqd/0-82    [000] ...1    66.299826: mmc_blk_rw_start: cmd=18,addr=0x01742000,size=0x00000008
+          <idle>-0     [000] ..s3    66.299991: mmc_blk_rw_end: cmd=18,addr=0x01742000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.300172: mmc_blk_erase_start: cmd=3,addr=0x01743000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    66.313018: mmc_blk_erase_end: cmd=3,addr=0x01743000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    66.316476: mmc_blk_rw_start: cmd=18,addr=0x01782000,size=0x00000008
+          <idle>-0     [000] ..s3    66.316641: mmc_blk_rw_end: cmd=18,addr=0x01782000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.316869: mmc_blk_erase_start: cmd=3,addr=0x01783000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    66.329795: mmc_blk_erase_end: cmd=3,addr=0x01783000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    66.333305: mmc_blk_rw_start: cmd=18,addr=0x017c2000,size=0x00000008
+          <idle>-0     [000] ..s3    66.333470: mmc_blk_rw_end: cmd=18,addr=0x017c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.333653: mmc_blk_erase_start: cmd=3,addr=0x017c3000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    66.346485: mmc_blk_erase_end: cmd=3,addr=0x017c3000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    66.349946: mmc_blk_rw_start: cmd=18,addr=0x01802000,size=0x00000008
+          <idle>-0     [000] ..s3    66.350111: mmc_blk_rw_end: cmd=18,addr=0x01802000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.350294: mmc_blk_erase_start: cmd=3,addr=0x01803020,size=0x0003efe0
+         mmcqd/0-82    [000] ...1    66.363089: mmc_blk_erase_end: cmd=3,addr=0x01803020,size=0x0003efe0
+         mmcqd/0-82    [000] ...1    66.366450: mmc_blk_rw_start: cmd=18,addr=0x01842000,size=0x00000008
+          <idle>-0     [000] ..s3    66.366611: mmc_blk_rw_end: cmd=18,addr=0x01842000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.366793: mmc_blk_erase_start: cmd=3,addr=0x01842ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.379653: mmc_blk_erase_end: cmd=3,addr=0x01842ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.382987: mmc_blk_rw_start: cmd=18,addr=0x01882000,size=0x00000008
+          <idle>-0     [000] ..s3    66.383152: mmc_blk_rw_end: cmd=18,addr=0x01882000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.383334: mmc_blk_erase_start: cmd=3,addr=0x01883000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    66.396156: mmc_blk_erase_end: cmd=3,addr=0x01883000,size=0x0003f000
+         mmcqd/0-82    [000] ...1    66.399533: mmc_blk_rw_start: cmd=18,addr=0x018c2000,size=0x00000008
+          <idle>-0     [000] ..s3    66.399695: mmc_blk_rw_end: cmd=18,addr=0x018c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.399877: mmc_blk_erase_start: cmd=3,addr=0x018c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.412722: mmc_blk_erase_end: cmd=3,addr=0x018c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.416159: mmc_blk_rw_start: cmd=18,addr=0x01902000,size=0x00000008
+          <idle>-0     [000] ..s3    66.416321: mmc_blk_rw_end: cmd=18,addr=0x01902000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.416501: mmc_blk_erase_start: cmd=3,addr=0x01902ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.429352: mmc_blk_erase_end: cmd=3,addr=0x01902ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.432979: mmc_blk_rw_start: cmd=18,addr=0x01942000,size=0x00000008
+          <idle>-0     [000] ..s3    66.433141: mmc_blk_rw_end: cmd=18,addr=0x01942000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.433322: mmc_blk_erase_start: cmd=3,addr=0x01942ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.446157: mmc_blk_erase_end: cmd=3,addr=0x01942ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.449711: mmc_blk_rw_start: cmd=18,addr=0x01982000,size=0x00000008
+          <idle>-0     [000] ..s3    66.449872: mmc_blk_rw_end: cmd=18,addr=0x01982000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.450054: mmc_blk_erase_start: cmd=3,addr=0x01982ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.462903: mmc_blk_erase_end: cmd=3,addr=0x01982ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.466393: mmc_blk_rw_start: cmd=18,addr=0x019c2000,size=0x00000008
+          <idle>-0     [000] ..s3    66.466555: mmc_blk_rw_end: cmd=18,addr=0x019c2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.466732: mmc_blk_erase_start: cmd=3,addr=0x019c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.479551: mmc_blk_erase_end: cmd=3,addr=0x019c2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.482884: mmc_blk_rw_start: cmd=18,addr=0x01a02000,size=0x00000008
+          <idle>-0     [000] ..s3    66.483045: mmc_blk_rw_end: cmd=18,addr=0x01a02000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.483223: mmc_blk_erase_start: cmd=3,addr=0x01a02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.496041: mmc_blk_erase_end: cmd=3,addr=0x01a02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.499568: mmc_blk_rw_start: cmd=18,addr=0x01a42000,size=0x00000008
+          <idle>-0     [000] ..s3    66.499730: mmc_blk_rw_end: cmd=18,addr=0x01a42000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.499915: mmc_blk_erase_start: cmd=3,addr=0x01a42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.512739: mmc_blk_erase_end: cmd=3,addr=0x01a42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.516246: mmc_blk_rw_start: cmd=18,addr=0x01a82000,size=0x00000008
+          <idle>-0     [000] ..s3    66.516408: mmc_blk_rw_end: cmd=18,addr=0x01a82000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.516590: mmc_blk_erase_start: cmd=3,addr=0x01a82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.529394: mmc_blk_erase_end: cmd=3,addr=0x01a82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.532936: mmc_blk_rw_start: cmd=18,addr=0x01ac2000,size=0x00000008
+          <idle>-0     [000] ..s3    66.533103: mmc_blk_rw_end: cmd=18,addr=0x01ac2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.533366: mmc_blk_erase_start: cmd=3,addr=0x01ac2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.551932: mmc_blk_erase_end: cmd=3,addr=0x01ac2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.555518: mmc_blk_rw_start: cmd=18,addr=0x01b02000,size=0x00000008
+          <idle>-0     [000] ..s3    66.555680: mmc_blk_rw_end: cmd=18,addr=0x01b02000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.555864: mmc_blk_erase_start: cmd=3,addr=0x01b02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.568720: mmc_blk_erase_end: cmd=3,addr=0x01b02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.572289: mmc_blk_rw_start: cmd=18,addr=0x01b42000,size=0x00000008
+          <idle>-0     [000] ..s3    66.572452: mmc_blk_rw_end: cmd=18,addr=0x01b42000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.572640: mmc_blk_erase_start: cmd=3,addr=0x01b42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.585472: mmc_blk_erase_end: cmd=3,addr=0x01b42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.589013: mmc_blk_rw_start: cmd=18,addr=0x01b82000,size=0x00000008
+          <idle>-0     [000] ..s3    66.589177: mmc_blk_rw_end: cmd=18,addr=0x01b82000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.589361: mmc_blk_erase_start: cmd=3,addr=0x01b82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.602230: mmc_blk_erase_end: cmd=3,addr=0x01b82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.605811: mmc_blk_rw_start: cmd=18,addr=0x01bc2000,size=0x00000008
+          <idle>-0     [000] ..s3    66.605978: mmc_blk_rw_end: cmd=18,addr=0x01bc2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.606237: mmc_blk_erase_start: cmd=3,addr=0x01bc2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.619123: mmc_blk_erase_end: cmd=3,addr=0x01bc2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.622525: mmc_blk_rw_start: cmd=18,addr=0x01c02000,size=0x00000008
+          <idle>-0     [000] ..s3    66.622686: mmc_blk_rw_end: cmd=18,addr=0x01c02000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.622869: mmc_blk_erase_start: cmd=3,addr=0x01c02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.635750: mmc_blk_erase_end: cmd=3,addr=0x01c02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.639180: mmc_blk_rw_start: cmd=18,addr=0x01c42000,size=0x00000008
+          <idle>-0     [000] ..s3    66.639341: mmc_blk_rw_end: cmd=18,addr=0x01c42000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.639524: mmc_blk_erase_start: cmd=3,addr=0x01c42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.652365: mmc_blk_erase_end: cmd=3,addr=0x01c42ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.655886: mmc_blk_rw_start: cmd=18,addr=0x01c82000,size=0x00000008
+          <idle>-0     [000] ..s3    66.656047: mmc_blk_rw_end: cmd=18,addr=0x01c82000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.656229: mmc_blk_erase_start: cmd=3,addr=0x01c82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.669069: mmc_blk_erase_end: cmd=3,addr=0x01c82ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.672492: mmc_blk_rw_start: cmd=18,addr=0x01cc2000,size=0x00000008
+          <idle>-0     [000] ..s3    66.672653: mmc_blk_rw_end: cmd=18,addr=0x01cc2000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.672835: mmc_blk_erase_start: cmd=3,addr=0x01cc2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.685704: mmc_blk_erase_end: cmd=3,addr=0x01cc2ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.689362: mmc_blk_rw_start: cmd=18,addr=0x01d02000,size=0x00000008
+          <idle>-0     [000] ..s3    66.689523: mmc_blk_rw_end: cmd=18,addr=0x01d02000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.689706: mmc_blk_erase_start: cmd=3,addr=0x01d02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.702548: mmc_blk_erase_end: cmd=3,addr=0x01d02ff8,size=0x0003f008
+         mmcqd/0-82    [000] ...1    66.705996: mmc_blk_rw_start: cmd=18,addr=0x01d42000,size=0x00000008
+          <idle>-0     [000] ..s3    66.706158: mmc_blk_rw_end: cmd=18,addr=0x01d42000,size=0x00000008
+         mmcqd/0-82    [000] ...1    66.706330: mmc_blk_erase_start: cmd=3,addr=0x01d42ff8,size=0x00015008
+         mmcqd/0-82    [000] ...1    66.714103: mmc_blk_erase_end: cmd=3,addr=0x01d42ff8,size=0x00015008
+         mmcqd/0-82    [000] ...1    67.055083: mmc_blk_rw_start: cmd=25,addr=0x00346400,size=0x00000008
+         mmcqd/0-82    [000] ..s3    67.055305: mmc_blk_rw_end: cmd=25,addr=0x00346400,size=0x00000008
+         mmcqd/0-82    [000] ...1    72.055236: mmc_blk_rw_start: cmd=25,addr=0x00542008,size=0x00000008
+         mmcqd/0-82    [000] ..s3    72.055404: mmc_blk_rw_end: cmd=25,addr=0x00542008,size=0x00000008
+         mmcqd/0-82    [000] ...1    72.056094: mmc_blk_rw_start: cmd=25,addr=0x005420c0,size=0x00000008
+         mmcqd/0-82    [000] ..s3    72.056225: mmc_blk_rw_end: cmd=25,addr=0x005420c0,size=0x00000008
+         mmcqd/0-82    [000] ...1    72.056859: mmc_blk_rw_start: cmd=25,addr=0x005420d0,size=0x00000008
+         mmcqd/0-82    [000] ..s3    72.056987: mmc_blk_rw_end: cmd=25,addr=0x005420d0,size=0x00000008
+         mmcqd/0-82    [000] ...1    72.057657: mmc_blk_rw_start: cmd=25,addr=0x00542118,size=0x00000008
+         mmcqd/0-82    [000] ..s3    72.057785: mmc_blk_rw_end: cmd=25,addr=0x00542118,size=0x00000008
+         mmcqd/0-82    [000] ...1    72.058561: mmc_blk_rw_start: cmd=25,addr=0x00542128,size=0x00000008
+         mmcqd/0-82    [000] ..s2    72.058755: mmc_blk_rw_end: cmd=25,addr=0x00542128,size=0x00000008
+         mmcqd/0-82    [000] ...1    72.059645: mmc_blk_rw_start: cmd=25,addr=0x00542140,size=0x00000008
+         mmcqd/0-82    [000] ..s3    72.059835: mmc_blk_rw_end: cmd=25,addr=0x00542140,size=0x00000008
+         mmcqd/0-82    [000] ...1    72.060601: mmc_blk_rw_start: cmd=25,addr=0x00544198,size=0x00000008
+         mmcqd/0-82    [000] ..s3    72.060792: mmc_blk_rw_end: cmd=25,addr=0x00544198,size=0x00000008
+         mmcqd/0-82    [000] ...1    72.061673: mmc_blk_rw_start: cmd=25,addr=0x00b82000,size=0x00000008
+         mmcqd/0-82    [000] ..s3    72.061865: mmc_blk_rw_end: cmd=25,addr=0x00b82000,size=0x00000008
+         mmcqd/0-82    [000] ...1    72.062756: mmc_blk_rw_start: cmd=25,addr=0x002c2000,size=0x00000010
+         mmcqd/0-82    [000] ..s3    72.063006: mmc_blk_rw_end: cmd=25,addr=0x002c2000,size=0x00000010
+         mmcqd/0-82    [000] ...1    72.525587: mmc_blk_rw_start: cmd=25,addr=0x002c6af8,size=0x00000008
+         mmcqd/0-82    [000] ..s3    72.525813: mmc_blk_rw_end: cmd=25,addr=0x002c6af8,size=0x00000008
+         mmcqd/0-82    [000] ...1   120.323646: mmc_blk_rw_start: cmd=25,addr=0x00b98140,size=0x00000008
+        Compiler-1337  [000] ..s4   120.323786: mmc_blk_rw_end: cmd=25,addr=0x00b98140,size=0x00000008
+         mmcqd/0-82    [000] ...1   120.326162: mmc_blk_rw_start: cmd=25,addr=0x002c6b00,size=0x00000048
+          <idle>-0     [000] ..s3   120.326635: mmc_blk_rw_end: cmd=25,addr=0x002c6b00,size=0x00000048
+         mmcqd/0-82    [000] ...1   120.327595: mmc_blk_rw_start: cmd=25,addr=0x002c6b48,size=0x00000008
+    AsyncTask #1-777   [000] ..s3   120.327691: mmc_blk_rw_end: cmd=25,addr=0x002c6b48,size=0x00000008
+         mmcqd/0-82    [000] ...1   122.485441: mmc_blk_rw_start: cmd=25,addr=0x00b91298,size=0x00000008
+         mmcqd/0-82    [000] ..s2   122.485746: mmc_blk_rw_end: cmd=25,addr=0x00b91298,size=0x00000008
+         mmcqd/0-82    [000] ...1   122.486369: mmc_blk_rw_start: cmd=25,addr=0x00b914b0,size=0x00000010
+         mmcqd/0-82    [000] ..s2   122.486656: mmc_blk_rw_end: cmd=25,addr=0x00b914b0,size=0x00000010
+         mmcqd/0-82    [000] ...1   122.487231: mmc_blk_rw_start: cmd=25,addr=0x00542120,size=0x00000008
+         mmcqd/0-82    [000] ..s3   122.487473: mmc_blk_rw_end: cmd=25,addr=0x00542120,size=0x00000008
+         mmcqd/0-82    [000] ...1   125.545654: mmc_blk_rw_start: cmd=25,addr=0x002c6b50,size=0x00000048
+          <idle>-0     [000] ..s3   125.547111: mmc_blk_rw_end: cmd=25,addr=0x002c6b50,size=0x00000048
+         mmcqd/0-82    [000] ...1   125.550617: mmc_blk_rw_start: cmd=25,addr=0x002c6b98,size=0x00000008
+          <idle>-0     [000] ..s4   125.550855: mmc_blk_rw_end: cmd=25,addr=0x002c6b98,size=0x00000008
diff --git a/tests/pagingtest/Android.mk b/tests/pagingtest/Android.mk
new file mode 100644
index 0000000..23ffea1
--- /dev/null
+++ b/tests/pagingtest/Android.mk
@@ -0,0 +1,22 @@
+local_target_dir := $(TARGET_OUT_DATA)/local/tmp
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=    \
+    pagingtest.c    \
+    mmap_test.c      \
+    pageinout_test.c \
+    thrashing_test.c
+
+LOCAL_CFLAGS := -std=gnu11
+
+LOCAL_MODULE:= pagingtest
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MODULE_PATH := $(local_target_dir)
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := pagingtest
+LOCAL_MODULE_STEM_64 := pagingtest64
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/pagingtest/mmap_test.c b/tests/pagingtest/mmap_test.c
new file mode 100644
index 0000000..d0d9846
--- /dev/null
+++ b/tests/pagingtest/mmap_test.c
@@ -0,0 +1,51 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "pagingtest.h"
+
+int mmap_test(int test_runs, unsigned long long alloc_size) {
+    void *buf;
+    int ret = -1;
+    int rc;
+    int i;
+    struct timeval begin_time, end_time, elapsed_time;
+    struct timeval total_time_mmap, total_time_munmap, total_time_in, total_time_out;
+
+    timerclear(&total_time_mmap);
+    timerclear(&total_time_munmap);
+    timerclear(&total_time_in);
+    timerclear(&total_time_out);
+
+    for (i = 0; i < test_runs; i++) {
+        gettimeofday(&begin_time, NULL);
+        buf = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+        gettimeofday(&end_time, NULL);
+        if (buf == ((void *)-1)) {
+            fprintf(stderr, "Failed to mmap anonymous memory: %s\n", strerror(errno));
+            goto err_map;
+        }
+        timersub(&end_time, &begin_time, &elapsed_time);
+        timeradd(&total_time_mmap, &elapsed_time, &total_time_mmap);
+
+        gettimeofday(&begin_time, NULL);
+        munmap(buf, alloc_size);
+        gettimeofday(&end_time, NULL);
+        timersub(&end_time, &begin_time, &elapsed_time);
+        timeradd(&total_time_mmap, &elapsed_time, &total_time_mmap);
+    }
+
+    printf("mmap: %llu us\n", total_time_mmap.tv_sec * USEC_PER_SEC + total_time_mmap.tv_usec);
+    printf("munmap: %llu us\n", total_time_munmap.tv_sec * USEC_PER_SEC + total_time_munmap.tv_usec);
+
+    ret = 0;
+    goto end;
+err:
+    munmap(buf, alloc_size);
+end:
+err_map:
+    return ret;
+}
diff --git a/tests/pagingtest/pageinout_test.c b/tests/pagingtest/pageinout_test.c
new file mode 100644
index 0000000..887794e
--- /dev/null
+++ b/tests/pagingtest/pageinout_test.c
@@ -0,0 +1,104 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "pagingtest.h"
+
+int pageinout_test(int test_runs, bool cache, unsigned long long file_size) {
+    int fd;
+    char tmpname[] = "pageinoutXXXXXX";
+    unsigned char *vec;
+    int i;
+    unsigned long long j;
+    volatile char *buf;
+    int ret = -1;
+    int rc;
+    struct timeval begin_time, end_time, elapsed_time, total_time_in, total_time_out;
+    long pagesize = sysconf(_SC_PAGE_SIZE);
+
+    timerclear(&total_time_in);
+    timerclear(&total_time_out);
+
+    fd = create_tmp_file(tmpname, file_size);
+    if (fd < 0) {
+        return -1;
+    }
+
+    vec = alloc_mincore_vec(file_size);
+    if (vec == NULL) {
+        goto err_alloc;
+    }
+
+    buf = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (buf == ((void *)-1)) {
+        fprintf(stderr, "Failed to mmap file: %s\n", strerror(errno));
+        goto err_mmap;
+    }
+
+    if (!check_caching((void *)buf, vec, file_size, false)) {
+        goto err;
+    }
+
+    if (!cache) {
+        //madvise and fadvise as random to prevent prefetching
+        rc = madvise((void *)buf, file_size, MADV_RANDOM) ||
+               posix_fadvise(fd, 0, file_size, POSIX_FADV_RANDOM);
+        if (rc) {
+            goto err;
+        }
+    }
+
+    for (i = 0; i < test_runs; i++) {
+        gettimeofday(&begin_time, NULL);
+        //read every page into the page cache
+        for (j = 0; j < file_size; j += pagesize) {
+            buf[j];
+        }
+        gettimeofday(&end_time, NULL);
+
+        timersub(&end_time, &begin_time, &elapsed_time);
+        timeradd(&total_time_in, &elapsed_time, &total_time_in);
+
+        if (!check_caching((void *)buf, vec, file_size, true)) {
+            goto err;
+        }
+
+        gettimeofday(&begin_time, NULL);
+        rc = madvise((void *)buf, file_size, MADV_DONTNEED) ||
+               posix_fadvise(fd, 0, file_size, POSIX_FADV_DONTNEED);
+        gettimeofday(&end_time, NULL);
+        if (rc) {
+            fprintf(stderr, "posix_fadvise/madvise DONTNEED failed\n");
+            goto err;
+        }
+
+        timersub(&end_time, &begin_time, &elapsed_time);
+        timeradd(&total_time_out, &elapsed_time, &total_time_out);
+
+        if (!check_caching((void *)buf, vec, file_size, false)) {
+            goto err;
+        }
+    }
+
+    printf("%scached page-in: %llu MB/s\n", cache ? "" : "un",
+             (file_size * test_runs * USEC_PER_SEC) /
+             (1024 * 1024 * (total_time_in.tv_sec * USEC_PER_SEC + total_time_in.tv_usec)));
+    printf("%scached page-out (clean): %llu MB/s\n", cache ? "" : "un",
+             (file_size * test_runs * USEC_PER_SEC) /
+             (1024 * 1024 * (total_time_out.tv_sec * USEC_PER_SEC + total_time_out.tv_usec)));
+
+    ret = 0;
+
+err:
+    munmap((void *)buf, file_size);
+err_mmap:
+    free(vec);
+err_alloc:
+    close(fd);
+    return ret;
+}
diff --git a/tests/pagingtest/pagingtest.c b/tests/pagingtest/pagingtest.c
new file mode 100644
index 0000000..158d8a3
--- /dev/null
+++ b/tests/pagingtest/pagingtest.c
@@ -0,0 +1,185 @@
+#include "pagingtest.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define TEST_RUNS 10
+#define ALLOC_SIZE (10 * 1024 * 1024)
+#define FILE_SIZE (10 * 1024 * 1024)
+
+int create_tmp_file(char *filename, off_t size) {
+    void *buf;
+    uint8_t *tmp_buf;
+    off_t tmp_size;
+    ssize_t rc;
+    int fd;
+    int urandom;
+
+    fd = mkstemp(filename);
+    if (fd < 0) {
+        fprintf(stderr, "unable to create temp file: %s\n", strerror(errno));
+        goto err_mkstemp;
+    }
+
+    urandom = open("/dev/urandom", O_RDONLY);
+    if (urandom < 0) {
+        fprintf(stderr, "unable to open urandom: %s\n", strerror(errno));
+        goto err_open;
+    }
+
+    if (unlink(filename)) {
+        fprintf(stderr, "unable to unlink temp file: %s\n", strerror(errno));
+        goto err_unlink;
+    }
+
+    if (ftruncate(fd, size)) {
+        fprintf(stderr, "unable to allocate temp file: %s\n", strerror(errno));
+        goto err_truncate;
+    }
+
+    buf = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
+    if (buf == (void *)-1) {
+        fprintf(stderr, "unable to mmap temp file: %s\n", strerror(errno));
+        goto err_mmap;
+    }
+
+    tmp_buf = buf;
+    tmp_size = size;
+    do {
+        rc = read(urandom, tmp_buf, tmp_size);
+
+        if (rc < 0) {
+            fprintf(stderr, "write random data failed: %s\n", strerror(errno));
+            goto err;
+        }
+
+        tmp_buf += rc;
+        tmp_size -= rc;
+    } while (tmp_size > 0);
+
+    if (madvise(buf, size, MADV_DONTNEED)) {
+        fprintf(stderr, "madvise DONTNEED failed: %s\n", strerror(errno));
+        goto err;
+    }
+
+    if (fsync(fd) < 0) {
+        fprintf(stderr, "fsync failed: %s\n", strerror(errno));
+        goto err;
+    }
+
+    rc = posix_fadvise(fd, 0, size, POSIX_FADV_DONTNEED);
+    if (rc) {
+        fprintf(stderr, "fadvise DONTNEED failed: %s\n", strerror(errno));
+        goto err;
+    }
+
+    munmap(buf, size);
+    close(urandom);
+    return fd;
+
+err:
+    munmap(buf, size);
+err_mmap:
+err_truncate:
+err_unlink:
+    close(urandom);
+err_open:
+    close(fd);
+err_mkstemp:
+    return -1;
+}
+
+unsigned char *alloc_mincore_vec(size_t size) {
+    unsigned char *vec;
+
+    vec = malloc(mincore_vec_len(size));
+    if (vec == NULL) {
+        fprintf(stderr, "malloc failed\n");
+    }
+
+    return vec;
+}
+
+bool check_caching(void *buf, unsigned char *vec, size_t size, bool is_cached) {
+    bool ret = true;
+    size_t i;
+
+    if (mincore(buf, size, vec)) {
+        fprintf(stderr, "mincore failed: %s\n", strerror(errno));
+        return false;
+    }
+
+    if (is_cached) {
+        for (i = 0; i < mincore_vec_len(size); i++) {
+            if (!(vec[i] & 0x1)) {
+                fprintf(stderr, "found an uncached page at page offset %zd\n", i);
+                ret = false;
+            }
+        }
+    } else {
+        for (i = 0; i < mincore_vec_len(size); i++) {
+            if (vec[i] & 0x1) {
+                fprintf(stderr, "found a cached page at page offset %zd\n", i);
+                ret = false;
+            }
+        }
+    }
+
+    return ret;
+}
+
+int main(int argc, char **argv) {
+    unsigned long long alloc_size = 0ULL;
+    unsigned long long file_size = 0ULL;
+    int test_runs = 0;
+    int rc;
+
+    //arguments: <program> [test_runs [alloc_size [file_size]]]
+    if (argc >= 2) {
+        test_runs = atoi(argv[1]);
+    }
+    if (test_runs <= 0) {
+        test_runs = TEST_RUNS;
+    }
+    if (argc >= 3) {
+        alloc_size = strtoull(argv[2], NULL, 10);
+    }
+    if (!alloc_size) {
+        alloc_size = ALLOC_SIZE;
+    }
+    if (argc >= 4) {
+        file_size = strtoull(argv[3], NULL, 10);
+    }
+    if (!file_size) {
+        file_size = FILE_SIZE;
+    }
+
+    rc = mmap_test(test_runs, alloc_size);
+    if (rc) {
+        return rc;
+    }
+    rc = pageinout_test(test_runs, true, file_size);
+    if (rc) {
+        return rc;
+    }
+    rc = pageinout_test(test_runs, false, file_size);
+    if (rc) {
+        return rc;
+    }
+    rc = thrashing_test(test_runs, true);
+    if (rc) {
+        return rc;
+    }
+    rc = thrashing_test(test_runs, false);
+
+    return rc;
+}
diff --git a/tests/pagingtest/pagingtest.h b/tests/pagingtest/pagingtest.h
new file mode 100644
index 0000000..a6f3d03
--- /dev/null
+++ b/tests/pagingtest/pagingtest.h
@@ -0,0 +1,20 @@
+#include <unistd.h>
+#include <stdbool.h>
+
+#ifndef __PAGINGTEST_H__
+#define __PAGINGTEST_H__
+#define USEC_PER_SEC 1000000ULL
+#define mincore_vec_len(size) (((size) + sysconf(_SC_PAGE_SIZE) - 1) / sysconf(_SC_PAGE_SIZE))
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
+//Helpers
+int create_tmp_file(char *filename, off_t size);
+unsigned char *alloc_mincore_vec(size_t size);
+bool check_caching(void *buf, unsigned char *vec, size_t size, bool is_cached);
+
+//Tests
+int mmap_test(int test_runs, unsigned long long alloc_size);
+int pageinout_test(int test_runs, bool cache, unsigned long long file_size);
+int thrashing_test(int test_runs, bool cache);
+
+#endif //__PAGINGTEST_H__
diff --git a/tests/pagingtest/thrashing_test.c b/tests/pagingtest/thrashing_test.c
new file mode 100644
index 0000000..0f4547f
--- /dev/null
+++ b/tests/pagingtest/thrashing_test.c
@@ -0,0 +1,87 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "pagingtest.h"
+
+#define LINESIZE 32
+
+int thrashing_test(int test_runs, bool cache) {
+    int fds[4] = {-1, -1, -1, -1};
+    char tmpnames[4][17] = { "thrashing1XXXXXX", "thrashing2XXXXXX", "thrashing3XXXXXX", "thrashing4XXXXXX" };
+    volatile char *bufs[4] = {0};
+    unsigned long long k;
+    int ret = -1;
+    struct timeval begin_time, end_time, elapsed_time, total_time;
+    unsigned long long filesize;
+    long num_pages;
+    long pagesize;
+
+    timerclear(&total_time);
+
+    num_pages = sysconf(_SC_PHYS_PAGES);
+    pagesize = sysconf(_SC_PAGE_SIZE);
+    if (num_pages < 0) {
+        fprintf(stderr, "failed to get the number of pages\n");
+        return -1;
+    }
+
+    filesize = num_pages * pagesize / (ARRAY_SIZE(fds) - 1);
+
+    for (size_t i = 0; i < ARRAY_SIZE(fds); i++) {
+        fds[i] = create_tmp_file(tmpnames[i], filesize);
+        if (fds[i] < 0) {
+            goto err_fd;
+        }
+    }
+
+    for (size_t i = 0; i < ARRAY_SIZE(fds); i++) {
+        bufs[i] = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fds[i], 0);
+        if (bufs[i] == ((void *)-1)) {
+            fprintf(stderr, "Failed to mmap file: %s\n", strerror(errno));
+            goto err;
+        }
+        if (!cache) {
+            //madvise and fadvise as random to prevent prefetching
+            ret = madvise((void *)bufs[i], filesize, MADV_RANDOM) ||
+                    posix_fadvise(fds[i], 0, filesize, POSIX_FADV_RANDOM);
+            if (ret) {
+                goto err;
+            }
+        }
+    }
+
+    for (int i = 0; i < test_runs; i++) {
+        for (size_t j = 0; j < ARRAY_SIZE(fds); j++) {
+            gettimeofday(&begin_time, NULL);
+            for (k = 0; k < filesize; k += pagesize) {
+                bufs[j][k];
+            }
+            gettimeofday(&end_time, NULL);
+
+            timersub(&end_time, &begin_time, &elapsed_time);
+            timeradd(&total_time, &elapsed_time, &total_time);
+        }
+    }
+
+    printf("%scached thrashing: %llu MB/s\n", cache ? "" : "un",
+             (filesize * ARRAY_SIZE(fds) * test_runs * USEC_PER_SEC) /
+             (1024 * 1024 * (total_time.tv_sec * USEC_PER_SEC + total_time.tv_usec)));
+
+    ret = 0;
+
+err:
+    for (size_t i = 0; i < ARRAY_SIZE(bufs) && bufs[i] != NULL; i++) {
+        munmap((void *)bufs[i], filesize);
+    }
+err_fd:
+    for (size_t i = 0; i < ARRAY_SIZE(fds) && fds[i] >= 0; i++) {
+        close(fds[i]);
+    }
+    return ret;
+}
diff --git a/tests/pftest/Android.mk b/tests/pftest/Android.mk
new file mode 100644
index 0000000..bedbd0c
--- /dev/null
+++ b/tests/pftest/Android.mk
@@ -0,0 +1,18 @@
+# Copyright 2010 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= pftest.c.arm
+
+
+LOCAL_SHARED_LIBRARIES := libc 
+
+LOCAL_MODULE:= pftest
+
+LOCAL_MODULE_TAGS := optional
+
+## LOCAL_CFLAGS += -fstack-protector-all
+LOCAL_CFLAGS += -fomit-frame-pointer
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/pftest/pftest.c b/tests/pftest/pftest.c
new file mode 100644
index 0000000..f5af894
--- /dev/null
+++ b/tests/pftest/pftest.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+#define N_PAGES (4096)
+
+#define WARMUP (1<<10)
+
+#define WORKLOAD (1<<24)
+
+int numPagesList[] = {
+  1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+  12, 14, 16, 18, 20, 24, 28, 30, 32, 34, 48, 62, 64, 66, 80,
+  96, 112, 128, 144, 160, 320, 480, 496, 512, 528, 544, 576, 640, 960,
+  1024, 2048, 3072, 4000,
+};
+
+static unsigned long long stop_watch()
+{
+    struct timespec t;
+    t.tv_sec = t.tv_nsec = 0;
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    return t.tv_sec*1000000000ULL + t.tv_nsec;
+}   
+
+int main()
+{
+    char *mem = malloc((N_PAGES+1) * 4096);
+    intptr_t *p;
+    int i;
+    unsigned int j;
+
+    /* Align to page start */
+    mem = (char *) ((intptr_t) (mem + 4096) & ~0xfff);
+
+    for (j = 0; j < sizeof(numPagesList)/sizeof(int); j++) {
+        int numPages = numPagesList[j];
+        int pageIdx = 0;
+        int entryOffset = 0;
+
+        /*
+         * page 0      page 1      page 2     ....     page N  
+         * ------      ------      ------              ------  
+         * word 0   -> word 0   -> word 0 ->  ....  -> word 0 -> (page 0/word 0)
+         *   :           :           :         :         :
+         * word 1023   word 1023   word 1023   :       word 1023
+         */
+        for (i = 0; i < numPages; i++) {
+            int nextPageIdx = (pageIdx + 1) % numPages;
+            /* Looks like spread the pointer across cache lines introduce noise
+             * to get to the asymptote
+             * int nextEntryOffset = (entryOffset + 32) % 1024;
+             */
+            int nextEntryOffset = entryOffset;
+
+            if (i != numPages -1) {
+                *(intptr_t *) (mem + 4096 * pageIdx + entryOffset) = 
+                    (intptr_t) (mem + 4096 * nextPageIdx + nextEntryOffset);
+            } else {
+                /* Last page - form the cycle */
+                *(intptr_t *) (mem + 4096 * pageIdx + entryOffset) =
+                    (intptr_t) &mem[0];
+            }
+
+            pageIdx = nextPageIdx;
+            entryOffset = nextEntryOffset;
+        }
+
+        /* Starting point of the pointer chase */
+        p = (intptr_t *) &mem[0];
+
+        /* Warmup (ie pre-thrash the memory system */
+        for (i = 0; i < WARMUP; i++) {
+            p = (intptr_t *) *p;
+        }
+
+        /* Real work */
+        unsigned long long t0 = stop_watch();
+        for (i = 0; i < WORKLOAD; i++) {
+            p = (intptr_t *) *p;
+        }
+        unsigned long long t1 = stop_watch();
+
+        /* To keep p from being optimized by gcc */
+        if (p) 
+            printf("%d, %f\n", numPages, (float) (t1 - t0) / WORKLOAD);
+    }
+    return 0;
+}
diff --git a/tests/schedtest/Android.mk b/tests/schedtest/Android.mk
new file mode 100644
index 0000000..036c9fe
--- /dev/null
+++ b/tests/schedtest/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	schedtest.c
+
+LOCAL_MODULE := schedtest
+LOCAL_CFLAGS := -Wno-unused-parameter
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/schedtest/schedtest.c b/tests/schedtest/schedtest.c
new file mode 100644
index 0000000..73ffadc
--- /dev/null
+++ b/tests/schedtest/schedtest.c
@@ -0,0 +1,49 @@
+/*
+** Copyright 2008 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.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+    int i;
+
+    struct timeval tv1;
+    struct timeval tv2;
+    long max = 0;
+    long avg = 0;
+
+    for(i = 1; ; i++) {
+        gettimeofday(&tv1, NULL);
+        usleep(1000);
+        gettimeofday(&tv2, NULL);
+
+        long usec = (tv2.tv_sec - tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec;
+        avg += usec;
+
+        if (usec > max) max = usec;
+        if (!(i % 1000)) {
+            avg /= 1000;
+            printf("max %ld\tavg %ld\n", max, avg);
+            max = 0;
+            avg = 0;
+        }
+    }
+    return 0;
+}
diff --git a/tests/sdcard/Android.mk b/tests/sdcard/Android.mk
new file mode 100644
index 0000000..d1e06f2
--- /dev/null
+++ b/tests/sdcard/Android.mk
@@ -0,0 +1,37 @@
+# Copyright (C) 2009 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.
+#
+# Build control file for Bionic's test programs
+# define the BIONIC_TESTS environment variable to build the test programs
+#
+
+ifdef SDCARD_TESTS
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES = \
+    stopwatch.cpp \
+    sysutil.cpp \
+    sdcard_perf_test.cpp \
+	testcase.cpp
+
+LOCAL_MODULE := sdcard_perf_test
+LOCAL_MODULE_TAGS := eng tests
+LOCAL_SHARED_LIBRARIES := libutils libhardware_legacy
+
+include $(BUILD_EXECUTABLE)
+
+endif  # SDCARD_TESTS
diff --git a/tests/sdcard/README b/tests/sdcard/README
new file mode 100644
index 0000000..210bb43
--- /dev/null
+++ b/tests/sdcard/README
@@ -0,0 +1,63 @@
+This directory contains tools to profile the sdcard performance.
+
+There are 2 parts to the tool:
+* A binary that runs on the device, exercises the sdcard and send
+  measurment data back to the host (sdcard_perf_test).
+* A host python script to plot the data.
+
+Additionally, there is script 'profile_sdcard.sh' that allows you
+to check how the sdcard scale with the number of processes.
+
+INSTALLATION
+============
+Build, install and mount debugfs. In this directory with a properly
+configured enviroment:
+
+  mm SDCARD_TESTS=1
+  adb remount
+  adb push $ANDROID_PRODUCT_OUT/system/bin/sdcard_perf_test /system/bin/sdcard_perf_test
+  adb shell mount -t debugfs none /sys/kernel/debug
+
+If you want to graph the results you need gnuplot and numpy:
+
+  sudo apt-get install gnuplot python-numpy python-numeric
+
+You need Gnuplot.py version 1.8 (not the one coming with ubuntu).
+Download it from the Gnuplot.py web site.  Extract to a temp
+directory, chdir and run:
+
+  sudo python setup.py install
+
+
+INVOCATION
+==========
+
+Run a simple test:
+
+  adb shell sdcard_perf_test --test=write --size=1000 --chunk-size=100 --procnb=1 --iterations=100
+
+This test will write 1000kbyte (1M) files using writes of 100kbytes (so 10 writes per file) using
+only 1 process for 100 times (100 files will be written on the sdcard).
+The test will not call sync to flush the writes.
+At the end of the test, some stats for the 'open' and 'write' system calls are written.
+
+If you want to plot the data, you need to use the --dump option and provide a file:
+
+  adb shell sdcard_perf_test --test=write --size=1000 --chunk-size=100 --procnb=1 --iterations=100 --dump >/tmp/data.txt
+
+PLOTTING
+========
+
+To plot the result using the iter number of the x axis:
+
+  plot_sdcard.py -i /tmp/data.txt
+
+To plot the result using time for the x axis:
+
+  plot_sdcard.py -t /tmp/data.txt
+
+To plot the result from the profiler:
+
+    profile_sdcard.sh
+    plot_sdcard.py -p
+
diff --git a/tests/sdcard/plot_sdcard.py b/tests/sdcard/plot_sdcard.py
new file mode 100755
index 0000000..0959465
--- /dev/null
+++ b/tests/sdcard/plot_sdcard.py
@@ -0,0 +1,334 @@
+#!/usr/bin/python2.5
+#
+# Copyright 2009, 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.
+
+
+"""plot_sdcard: A module to plot the results of an sdcard perf test.
+
+Requires Gnuplot python v 1.8
+
+Typical usage:
+ -t x axis is time
+ -i x axis is iteration
+ -p profile data generated by profile_sdcard.sh
+
+./plot_sdcard.py -t /tmp/data.txt
+./plot_sdcard.py -i /tmp/data.txt
+./plot_sdcard.py -p
+
+python interpreter
+>>> import plot_sdcard as p
+>>> (metadata, data) = p.Parse('/tmp/data.txt')
+>>> p.PlotIterations(metadata, data)
+>>> p.PlotTimes(metadata, data)
+
+"""
+
+import getopt
+from itertools import izip
+import re
+import sys
+import Gnuplot
+import numpy
+
+
+class DataSet(object):
+  """Dataset holds the summary and data (time,value pairs)."""
+
+  def __init__(self, line):
+    res = re.search(('# StopWatch ([\w]+) total/cumulative '
+                     'duration ([0-9.]+). Samples: ([0-9]+)'), line)
+    self.time = []
+    self.data = []
+    self.name = res.group(1)
+    self.duration = float(res.group(2))
+    self.iteration = int(res.group(3))
+    self.summary = re.match('([a-z_]+)_total', self.name)
+
+  def __repr__(self):
+    return str(zip(self.time, self.data))
+
+  def Add(self, time, value):
+    self.time.append(time)
+    self.data.append(value)
+
+  def RescaleTo(self, length):
+    factor = len(self.data) / length
+
+    if factor > 1:
+      new_time = []
+      new_data = []
+      accum = 0.0
+      idx = 1
+      for t, d in izip(self.time, self.data):
+        accum += d
+        if idx % factor == 0:
+          new_time.append(t)
+          new_data.append(accum / factor)
+          accum = 0
+        idx += 1
+      self.time = new_time
+      self.data = new_data
+
+
+class Metadata(object):
+  def __init__(self):
+    self.kernel = ''
+    self.command_line = ''
+    self.sched = ''
+    self.name = ''
+    self.fadvise = ''
+    self.iterations = 0
+    self.duration = 0.0
+    self.complete = False
+
+  def Parse(self, line):
+    if line.startswith('# Kernel:'):
+      self.kernel = re.search('Linux version ([0-9.]+-[^ ]+)', line).group(1)
+    elif line.startswith('# Command:'):
+      self.command_line = re.search('# Command: [/\w_]+ (.*)', line).group(1)
+      self.command_line = self.command_line.replace(' --', '-')
+      self.command_line = self.command_line.replace(' -d', '')
+      self.command_line = self.command_line.replace('--test=', '')
+    elif line.startswith('# Iterations'):
+      self.iterations = int(re.search('# Iterations: ([0-9]+)', line).group(1))
+    elif line.startswith('# Fadvise'):
+      self.fadvise = re.search('# Fadvise: ([\w]+)', line).group(1)
+    elif line.startswith('# Sched'):
+      self.sched = re.search('# Sched features: ([\w]+)', line).group(1)
+      self.complete = True
+
+  def AsTitle(self):
+    return '%s-duration:%f\\n-%s\\n%s' % (
+        self.kernel, self.duration, self.command_line, self.sched)
+
+  def UpdateWith(self, dataset):
+    self.duration = max(self.duration, dataset.duration)
+    self.name = dataset.name
+
+
+def Parse(filename):
+  """Parse a file with the collected data.
+
+  The data must be in 2 rows (x,y).
+
+  Args:
+    filename: Full path to the file.
+  """
+
+  f = open(filename, 'r')
+
+  metadata = Metadata()
+  data = []  # array of dataset
+  dataset = None
+
+  for num, line in enumerate(f):
+    try:
+      line = line.strip()
+      if not line: continue
+
+      if not metadata.complete:
+        metadata.Parse(line)
+        continue
+
+      if re.match('[a-z_]', line):
+        continue
+
+      if line.startswith('# StopWatch'):  # Start of a new dataset
+        if dataset:
+          if dataset.summary:
+            metadata.UpdateWith(dataset)
+          else:
+            data.append(dataset)
+
+        dataset = DataSet(line)
+        continue
+
+      if line.startswith('#'):
+        continue
+
+      # must be data at this stage
+      try:
+        (time, value) = line.split(None, 1)
+      except ValueError:
+        print 'skipping line %d: %s' % (num, line)
+        continue
+
+      if dataset and not dataset.summary:
+        dataset.Add(float(time), float(value))
+
+    except Exception:
+      print 'Error parsing line %d' % num, sys.exc_info()[0]
+      raise
+  data.append(dataset)
+  if not metadata.complete:
+    print """Error missing metadata. Did you mount debugfs?
+    [adb shell mount -t debugfs none /sys/kernel/debug]"""
+    sys.exit(1)
+  return (metadata, data)
+
+
+def PlotIterations(metadata, data):
+  """Plot the duration of the ops against iteration.
+
+  If you are plotting data with widely different runtimes you probably want to
+  use PlotTimes instead.
+
+  For instance when readers and writers are in the same mix, the
+  readers will go thru 100 iterations much faster than the
+  writers. The load test tries to be smart about that but the final
+  iterations of the writers will likely be done w/o any influence from
+  the readers.
+
+  Args:
+    metadata: For the graph's title.
+    data: pair of to be plotted.
+  """
+
+  gp = Gnuplot.Gnuplot(persist=1)
+  gp('set data style lines')
+  gp.clear()
+  gp.xlabel('iterations')
+  gp.ylabel('duration in second')
+  gp.title(metadata.AsTitle())
+  styles = {}
+  line_style = 1
+
+  for dataset in data:
+    dataset.RescaleTo(metadata.iterations)
+    x = numpy.arange(len(dataset.data), dtype='int_')
+    if not dataset.name in styles:
+      styles[dataset.name] = line_style
+      line_style += 1
+      d = Gnuplot.Data(x, dataset.data,
+                       title=dataset.name,
+                       with_='lines ls %d' % styles[dataset.name])
+    else:  # no need to repeat a title that exists already.
+      d = Gnuplot.Data(x, dataset.data,
+                       with_='lines ls %d' % styles[dataset.name])
+
+    gp.replot(d)
+  gp.hardcopy('/tmp/%s-%s-%f.png' %
+              (metadata.name, metadata.kernel, metadata.duration),
+              terminal='png')
+
+
+def PlotTimes(metadata, data):
+  """Plot the duration of the ops against time elapsed.
+
+  Args:
+    metadata: For the graph's title.
+    data: pair of to be plotted.
+  """
+
+  gp = Gnuplot.Gnuplot(persist=1)
+  gp('set data style impulses')
+  gp('set xtics 1')
+  gp.clear()
+  gp.xlabel('seconds')
+  gp.ylabel('duration in second')
+  gp.title(metadata.AsTitle())
+  styles = {}
+  line_style = 1
+
+  for dataset in data:
+    x = numpy.array(dataset.time, dtype='float_')
+    if not dataset.name in styles:
+      styles[dataset.name] = line_style
+      line_style += 1
+      d = Gnuplot.Data(x, dataset.data,
+                       title=dataset.name,
+                       with_='impulses ls %d' % styles[dataset.name])
+    else:  # no need to repeat a title that exists already.
+      d = Gnuplot.Data(x, dataset.data,
+                       with_='impulses ls %d' % styles[dataset.name])
+
+    gp.replot(d)
+  gp.hardcopy('/tmp/%s-%s-%f.png' %
+              (metadata.name, metadata.kernel, metadata.duration),
+              terminal='png')
+
+
+def PlotProfile():
+  """Plot the time of a run against the number of processes."""
+  (metadata, data) = Parse('/tmp/sdcard-scalability.txt')
+  gp = Gnuplot.Gnuplot(persist=1)
+  gp('set data style impulses')
+  gp('set xtics 1')
+  gp('set pointsize 2')
+  gp.clear()
+  gp.xlabel('writer process')
+  gp.ylabel('duration in second')
+  gp.title(metadata.AsTitle())
+
+  dataset = data[0]
+  x = numpy.array(dataset.time, dtype='int_')
+  d = Gnuplot.Data(x, dataset.data,
+                   title=dataset.name,
+                   with_='linespoints')
+  gp.replot(d)
+  gp.hardcopy('/tmp/%s-%s-%f.png' %
+              (metadata.name, metadata.kernel, metadata.duration),
+              terminal='png')
+
+
+def Usage():
+  """Print this module's usage."""
+  print """
+  To plot the result using the iter number of the x axis:
+
+    plot_sdcard.py -i /tmp/data.txt
+
+  To plot the result using time for the x axis:
+
+    plot_sdcard.py -t /tmp/data.txt
+
+  To plot the result from the profiler:
+
+    profile_sdcard.sh
+    plot_sdcard.py -p
+
+  """
+  sys.exit(2)
+
+
+def main(argv):
+  try:
+    (optlist, args) = getopt.getopt(argv[1:],
+                                    'itp', ['iteration', 'time', 'profile'])
+  except getopt.GetoptError, err:
+    print str(err)
+    Usage()
+
+  for flag, val in optlist:
+    if flag in ('-i', '--iteration'):
+      (metadata, data) = Parse(args[0])
+      PlotIterations(metadata, data)
+      sys.exit(0)
+    elif flag in ('-t', '--time'):
+      (metadata, data) = Parse(args[0])
+      PlotTimes(metadata, data)
+      sys.exit(0)
+    elif flag in ('-p', '--profile'):
+      PlotProfile()
+      sys.exit(0)
+  Usage()
+
+
+if __name__ == '__main__':
+  if Gnuplot.__version__ != "1.8":
+    print "Gnuplot should be 1.8. See REAME file"
+    sys.exit(2)
+  main(sys.argv)
diff --git a/tests/sdcard/profile_sdcard.sh b/tests/sdcard/profile_sdcard.sh
new file mode 100755
index 0000000..4629c91
--- /dev/null
+++ b/tests/sdcard/profile_sdcard.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+# Copyright 2009, 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.
+
+# Run a bunch of test on the sdcard to establish a performance profile.
+
+print_kernel() {
+  adb shell cat /proc/version
+}
+print_sched_features() {
+  adb shell cat /sys/kernel/debug/sched_features
+}
+
+# Use dd to get the raw speed of the card
+block_level() {
+  true
+}
+
+# Time to run a test vs number of processes
+scalability() {
+  local file="/tmp/sdcard-scalability.txt"
+  rm -f ${file}
+  echo "# Scalability tests" | tee -a ${file}
+  echo "# Kernel: $(print_kernel)" | tee -a ${file}
+  echo "# Sched features: $(print_sched_features)" | tee -a ${file}
+  echo "# StopWatch scalability total/cumulative duration 0.0 Samples: 1" | tee -a ${file}
+  echo "# Process Time" | tee -a ${file}
+  for p in $(seq 1 8); do
+    adb shell sdcard_perf_test --test=write --procnb=${p} --size=1000 --chunk-size=100 --iterations=50 >/tmp/tmp-sdcard.txt
+    local t=$(grep 'write_total' /tmp/tmp-sdcard.txt | tail -n 1 | cut -f 6 -d ' ')
+    echo "$p $t" | tee -a ${file}
+  done
+
+}
+
+# Readers and writers should not starve each others.
+fairness() {
+  # Check readers finished before writers.
+  # Find the time of the last read op.
+  # Count how many writes and how many read happend
+  # during that period, do the ratio.
+  true
+}
+
+#######################################################################
+# MAIN
+
+echo "Make sure debugfs is mounted on the device."
+block_level
+scalability
+fairness
+
+
diff --git a/tests/sdcard/sdcard_perf_test.cpp b/tests/sdcard/sdcard_perf_test.cpp
new file mode 100644
index 0000000..c93c52b
--- /dev/null
+++ b/tests/sdcard/sdcard_perf_test.cpp
@@ -0,0 +1,737 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE 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.
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <string.h>
+#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 output is either a
+// human readable report or the raw timing samples that can be
+// processed using another tool.
+//
+// Needs debugfs:
+//   adb root;
+//   adb shell mount -t debugfs none /sys/kernel/debug
+//
+// The following tests are defined (value of the --test flag):
+//  write:       Open a file write some random data and close.
+//  read:        Open a file read it and close.
+//  read_write:  Combine readers and writers.
+//  open_create: Open|create an non existing file.
+//
+// For each run you can control how many processes will run the test in
+// parallel to simulate a real load (--procnb flag)
+//
+// For each process, the test selected will be executed many time to
+// get a meaningful average/min/max (--iterations flag)
+//
+// Use --dump to also get the raw data.
+//
+// For read/write tests, size is the number of Kbytes to use.
+//
+// To build: mmm system/extras/tests/sdcard/Android.mk SDCARD_TESTS=1
+//
+// Examples:
+// adb shell /system/bin/sdcard_perf_test --test=read --size=1000 --chunk-size=100 --procnb=1 --iterations=10 --dump > /tmp/data.txt
+// adb shell /system/bin/sdcard_perf_test --test=write --size=1000 --chunk-size=100 --procnb=1 --iterations=100 --dump > /tmp/data.txt
+//
+// To watch the memory: cat /proc/meminfo
+// If the phone crashes, look at /proc/last_kmsg on reboot.
+//
+// TODO: It would be cool if we could play with various fadvise()
+// strategies in here to see how tweaking read-ahead changes things.
+//
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+// TODO: No clue where fadvise is. Disabled for now.
+#define FADVISE(fd, off, len, advice) (void)0
+
+#ifndef min
+#define min(a,b) (((a)>(b))?(b):(a))
+#endif
+
+namespace  {
+using android::kernelVersion;
+using android::kMinKernelVersionBufferSize;
+using android::schedFeatures;
+using android::kMinSchedFeaturesBufferSize;
+using android_test::StopWatch;
+using android::writePidAndWaitForReply;
+using android::waitForChildrenAndSignal;
+using android::waitForChildrenOrExit;
+using android_test::TestCase;
+
+const char *kAppName = "sdcard_perf_test";
+const char *kTestDir = "/sdcard/perf";
+const bool kVerbose = false;
+
+// Used by getopt to parse the command line.
+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'},
+    {"dump",  no_argument, 0, 'd'},
+    {"cpu-scaling",  no_argument, 0, 'c'},
+    {"sync",  required_argument, 0, 'f'},
+    {"truncate", no_argument, 0, 'e'},
+    {"no-new-fair-sleepers", no_argument, 0, 'z'},
+    {"no-normalized-sleepers", no_argument, 0, 'Z'},
+    {"fadvise", required_argument, 0, 'a'},
+    {"help", no_argument, 0, 'h'},
+    {0, 0, 0, 0},
+};
+
+void usage()
+{
+    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"
+           "  -c --cpu-scaling: Enable cpu scaling.\n"
+           "  -s --sync: fsync|sync Use fsync or sync in write test. Default: no sync call.\n"
+           "  -e --truncate:    Truncate to size the file on creation.\n"
+           "  -z --no-new-fair-sleepers: Turn them off. You need to mount debugfs.\n"
+           "  -Z --no-normalized-sleepers: Turn them off. You need to mount debugfs.\n"
+           "  -a --fadvise:     Specify an fadvise policy (not supported).\n"
+           );
+}
+
+// Print command line, pid, kernel version, OOM adj and scheduler.
+void printHeader(int argc, char **argv, const TestCase& testCase)
+{
+    printf("# Command: ");
+    for (int i = 0; i < argc; ++i)
+    {
+        printf("%s ", argv[i]);
+    }
+    printf("\n");
+
+    printf("# Pid: %d\n", getpid());
+
+    {
+        char buffer[kMinKernelVersionBufferSize] = {0, };
+        if (kernelVersion(buffer, sizeof(buffer)) > 0)
+        {
+            printf("# Kernel: %s", buffer);
+        }
+    }
+
+    // Earlier on, running this test was crashing the phone. It turned
+    // out that it was using too much memory but its oom_adj value was
+    // -17 which means disabled. -16 is the system_server and 0 is
+    // typically what applications run at. The issue is that adb runs
+    // at -17 and so is this test. We force oom_adj to 0 unless the
+    // oom_adj option has been used.
+    // TODO: We talked about adding an option to control oom_adj, not
+    // sure if we still need that.
+    int oomAdj = android::pidOutOfMemoryAdj();
+
+    printf("# Oom_adj: %d ", oomAdj);
+    if (oomAdj < 0)
+    {
+        android::setPidOutOfMemoryAdj(0);
+        printf("adjuted to %d", android::pidOutOfMemoryAdj());
+    }
+    printf("\n");
+
+    {
+        char buffer[kMinSchedFeaturesBufferSize] = {0, };
+        if (schedFeatures(buffer, sizeof(buffer)) > 0)
+        {
+            printf("# Sched features: %s", buffer);
+        }
+    }
+    printf("# Fadvise: %s\n", testCase.fadviseAsStr());
+}
+
+// Remove all the files under kTestDir and clear the caches.
+void cleanup() {
+    android::resetDirectory(kTestDir);
+    android::syncAndDropCaches();  // don't pollute runs.
+}
+
+// @param argc, argv have a wild guess.
+// @param[out] testCase Structure built from the cmd line args.
+void parseCmdLine(int argc, char **argv, TestCase *testCase)\
+{
+    int c;
+
+    while(true)
+    {
+        // getopt_long stores the option index here.
+        int option_index = 0;
+
+        c = getopt_long (argc, argv,
+                         "hS:s:D:i:p:t:dcf:ezZa:",
+                         long_options,
+                         &option_index);
+        // Detect the end of the options.
+        if (c == -1) break;
+
+        switch (c)
+        {
+            case 's':
+                testCase->setDataSize(atoi(optarg) * 1024);
+                break;
+            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());
+                break;
+            case 'p':
+                testCase->setNproc(atoi(optarg));
+                printf("# Proc nb: %d\n", testCase->nproc());
+                break;
+            case 't':
+                testCase->setTypeFromName(optarg);
+                printf("# Test name %s\n", testCase->name());
+                break;
+            case 'd':
+                testCase->setDump();
+                break;
+            case 'c':
+                printf("# Cpu scaling is on\n");
+                testCase->setCpuScaling();
+                break;
+            case 'f':
+                if (strcmp("sync", optarg) == 0) {
+                    testCase->setSync(TestCase::SYNC);
+                } else if (strcmp("fsync", optarg) == 0) {
+                    testCase->setSync(TestCase::FSYNC);
+                }
+                break;
+            case 'e':  // e for empty
+                printf("# Will truncate to size\n");
+                testCase->setTruncateToSize();
+                break;
+            case 'z':  // no new fair sleepers
+                testCase->setNewFairSleepers(false);
+                break;
+            case 'Z':  // no normalized sleepers
+                testCase->setNormalizedSleepers(false);
+                break;
+            case 'a':  // fadvise
+                testCase->setFadvise(optarg);
+                break;
+            case 'h':
+                usage();
+                exit(0);
+            default:
+                fprintf(stderr, "Unknown option %s\n", optarg);
+                exit(EXIT_FAILURE);
+        }
+    }
+}
+
+// ----------------------------------------------------------------------
+// READ TEST
+
+// Read a file.  We use a new file each time to avoid any caching
+// effect that would happen if we were reading the same file each
+// time.
+// @param chunk buffer large enough where the chunk read are written.
+// @param idx iteration number.
+// @param testCase has all the timers and paramters to run the test.
+
+bool readData(char *const chunk, const int idx, TestCase *testCase)
+{
+    char filename[80] = {'\0',};
+
+    sprintf(filename, "%s/file-%d-%d", kTestDir, idx, getpid());
+
+    testCase->openTimer()->start();
+    int fd = open(filename, O_RDONLY);
+    testCase->openTimer()->stop();
+
+    if (fd < 0)
+    {
+        fprintf(stderr, "Open read only failed.");
+        return false;
+    }
+    FADVISE(fd, 0, 0, testCase->fadvise());
+
+    size_t left = testCase->dataSize();
+    pid_t *pid = (pid_t*)chunk;
+    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;
+        }
+
+        testCase->readTimer()->start();
+        while (chunk_size > 0)
+        {
+            ssize_t s = read(fd, dest, chunk_size);
+            if (s < 0)
+            {
+                fprintf(stderr, "Failed to read.\n");
+                close(fd);
+                return false;
+            }
+            chunk_size -= s;
+            dest += s;
+        }
+        testCase->readTimer()->stop();
+    }
+    close(fd);
+    if (testCase->pid() != *pid)
+    {
+        fprintf(stderr, "Wrong pid found @ read block %x != %x\n", testCase->pid(), *pid);
+        return false;
+    }
+    else
+    {
+        return true;
+    }
+}
+
+
+bool testRead(TestCase *testCase) {
+    // Setup the testcase by writting some dummy files.
+    const size_t size = testCase->dataSize();
+    size_t chunk_size = testCase->chunkSize();
+    char *const chunk = new char[chunk_size];
+
+    memset(chunk, 0xaa, chunk_size);
+    *((pid_t *)chunk) = testCase->pid(); // write our pid at the beginning of each chunk
+
+    size_t iter = testCase->iter();
+
+    // since readers are much faster we increase the number of
+    // iteration to last longer and have concurrent read/write
+    // thoughout the whole test.
+    if (testCase->type() == TestCase::READ_WRITE)
+    {
+        iter *= TestCase::kReadWriteFactor;
+    }
+
+    for (size_t i = 0; i < iter; ++i)
+    {
+        char filename[80] = {'\0',};
+
+        sprintf(filename, "%s/file-%d-%d", kTestDir, i, testCase->pid());
+        int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU);
+
+        size_t left = size;
+        while (left > 0)
+        {
+            if (chunk_size > left)
+            {
+                chunk_size = left;
+            }
+            ssize_t written = write(fd, chunk, chunk_size);
+            if (written < 0)
+            {
+                fprintf(stderr, "Write failed %d %s.", errno, strerror(errno));
+                return false;
+            }
+            left -= written;
+        }
+        close(fd);
+    }
+    if (kVerbose) printf("Child %d all chunk written\n", testCase->pid());
+
+    android::syncAndDropCaches();
+    testCase->signalParentAndWait();
+
+    // Start the read test.
+    testCase->testTimer()->start();
+    for (size_t i = 0; i < iter; ++i)
+    {
+        if (!readData(chunk, i, testCase))
+        {
+            return false;
+        }
+    }
+    testCase->testTimer()->stop();
+
+    delete [] chunk;
+    return true;
+}
+
+// ----------------------------------------------------------------------
+// WRITE TEST
+
+bool writeData(const char *const chunk, const int idx, TestCase *testCase) {
+    char filename[80] = {'\0',};
+
+    sprintf(filename, "%s/file-%d-%d", kTestDir, idx, getpid());
+    testCase->openTimer()->start();
+    int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU);  // no O_TRUNC, see header comment
+    testCase->openTimer()->stop();
+
+    if (fd < 0)
+    {
+        fprintf(stderr, "Open write failed.");
+        return false;
+    }
+    FADVISE(fd, 0, 0, testCase->fadvise());
+
+    if (testCase->truncateToSize())
+    {
+        testCase->truncateTimer()->start();
+        ftruncate(fd, testCase->dataSize());
+        testCase->truncateTimer()->stop();
+    }
+
+    size_t left = testCase->dataSize();
+    while (left > 0)
+    {
+        const char *dest = chunk;
+        size_t chunk_size = testCase->chunkSize();
+
+        if (chunk_size > left)
+        {
+            chunk_size = left;
+            left = 0;
+        }
+        else
+        {
+            left -= chunk_size;
+        }
+
+
+        testCase->writeTimer()->start();
+        while (chunk_size > 0)
+        {
+            ssize_t s = write(fd, dest, chunk_size);
+            if (s < 0)
+            {
+                fprintf(stderr, "Failed to write.\n");
+                close(fd);
+                return false;
+            }
+            chunk_size -= s;
+            dest += s;
+        }
+        testCase->writeTimer()->stop();
+    }
+
+    if (TestCase::FSYNC == testCase->sync())
+    {
+        testCase->syncTimer()->start();
+        fsync(fd);
+        testCase->syncTimer()->stop();
+    }
+    else if (TestCase::SYNC == testCase->sync())
+    {
+        testCase->syncTimer()->start();
+        sync();
+        testCase->syncTimer()->stop();
+    }
+    close(fd);
+    return true;
+}
+
+bool testWrite(TestCase *testCase)
+{
+    const size_t size = testCase->dataSize();
+    size_t chunk_size = testCase->chunkSize();
+    char *data = new char[chunk_size];
+
+    memset(data, 0xaa, chunk_size);
+    // TODO: write the pid at the beginning like in the write
+    // test. Have a mode where we check the write was correct.
+    testCase->signalParentAndWait();
+
+    testCase->testTimer()->start();
+    for (size_t i = 0; i < testCase->iter(); ++i)
+    {
+        if (!writeData(data, i, testCase))
+        {
+            return false;
+        }
+    }
+    testCase->testTimer()->stop();
+    delete [] data;
+    return true;
+}
+
+
+// ----------------------------------------------------------------------
+// READ WRITE
+
+// Mix of read and write test. Even PID run the write test. Odd PID
+// the read test. Not fool proof but work most of the time.
+bool testReadWrite(TestCase *testCase)
+{
+    if (getpid() & 0x1) {
+        return testRead(testCase);
+    } else {
+        return testWrite(testCase);
+    }
+}
+
+// ----------------------------------------------------------------------
+// OPEN CREATE TEST
+
+bool testOpenCreate(TestCase *testCase)
+{
+    char filename[80] = {'\0',};
+
+    testCase->signalParentAndWait();
+    testCase->testTimer()->start();
+
+    for (size_t i = 0; i < testCase->iter(); ++i)
+    {
+        sprintf(filename, "%s/file-%d-%d", kTestDir, i, testCase->pid());
+
+        int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU);
+        FADVISE(fd, 0, 0, testCase->fadvise());
+
+        if (testCase->truncateToSize())
+        {
+            ftruncate(fd, testCase->dataSize());
+        }
+        if (fd < 0)
+        {
+            return false;
+        }
+        close(fd);
+    }
+    testCase->testTimer()->stop();
+    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)
+{
+    android_test::TestCase testCase(kAppName);
+
+    cleanup();
+
+    parseCmdLine(argc, argv, &testCase);
+    printHeader(argc, argv, testCase);
+
+    printf("# File size %d kbytes\n", testCase.dataSize() / 1024);
+    printf("# Chunk size %d kbytes\n", testCase.chunkSize() / 1024);
+    printf("# Sync: %s\n", testCase.syncAsStr());
+
+    if (!testCase.cpuScaling())
+    {
+        android::disableCpuScaling();
+    }
+
+    switch(testCase.type()) {
+        case TestCase::WRITE:
+            testCase.mTestBody = testWrite;
+            break;
+        case TestCase::READ:
+            testCase.mTestBody = testRead;
+            break;
+        case TestCase::OPEN_CREATE:
+            testCase.mTestBody = testOpenCreate;
+            break;
+        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);
+    }
+
+    testCase.createTimers();
+
+    bool ok;
+
+    ok = testCase.runTest();
+
+    cleanup();
+    if (!ok)
+    {
+        printf("error %d %s", errno, strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+    else
+    {
+        exit(EXIT_SUCCESS);
+    }
+}
diff --git a/tests/sdcard/stopwatch.cpp b/tests/sdcard/stopwatch.cpp
new file mode 100644
index 0000000..77768d6
--- /dev/null
+++ b/tests/sdcard/stopwatch.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE 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.
+ */
+
+
+#include <malloc.h>
+#include <stdio.h>
+#include <time.h>
+#include "stopwatch.h"
+#include <math.h>
+
+#define SNPRINTF_OR_RETURN(str, size, format, ...) {                    \
+        int len = snprintf((str), (size), (format), ## __VA_ARGS__);    \
+        if (len < 0) return;                                            \
+        if (len > static_cast<int>(size)) {                             \
+            fprintf(stderr, "Not enough space\n");                      \
+            return;                                                     \
+        } else {                                                        \
+            (size) -= len; (str) += len;                                \
+        }                                                               \
+    }
+
+namespace {
+const bool kVerbose = false;
+bool printRaw = false;
+}
+
+namespace android_test {
+
+StopWatch::StopWatch(const char *name, size_t capacity)
+    : mName(strdup(name)), mNum(0), mData(NULL), mDataLen(0), mCapacity(capacity * 2),
+      mSizeKbytes(0), mAlreadyPrinted(false), mPrintRaw(false),
+      mDuration(0.0), mDeviation(0.0),
+      mMinDuration(0.0), mMinIdx(0),
+      mMaxDuration(0.0), mMaxIdx(0),
+      mDeltas(NULL), mUsed(false)
+{
+    mStart.tv_sec = 0;
+    mStart.tv_nsec = 0;
+    mData = (Measurement *) malloc(mCapacity * sizeof(Measurement));
+}
+
+StopWatch::~StopWatch()
+{
+    if (mUsed && !mAlreadyPrinted)
+    {
+        fprintf(stderr, "Discarding data for %s\n", mName);
+    }
+    free(mData);
+    free(mName);
+    delete [] mDeltas;
+}
+
+void StopWatch::start()
+{
+    checkCapacity();
+    clock_gettime(CLOCK_MONOTONIC, &mData[mDataLen].mTime);
+    mData[mDataLen].mIsStart = true;
+    if (!mUsed)
+    {
+        mStart = mData[mDataLen].mTime; // mDataLen should be 0
+        mUsed = true;
+    }
+    ++mNum;
+    ++mDataLen;
+}
+
+void StopWatch::stop()
+{
+    checkCapacity();
+    clock_gettime(CLOCK_MONOTONIC, &mData[mDataLen].mTime);
+    mData[mDataLen].mIsStart = false;
+    ++mDataLen;
+}
+
+void StopWatch::setPrintRawMode(bool raw)
+{
+    printRaw = raw;
+}
+
+
+void StopWatch::sprint(char **str, size_t *size)
+{
+    if (kVerbose) fprintf(stderr, "printing\n");
+    mAlreadyPrinted = true;
+    if (0 == mDataLen)
+    {
+        return;
+    }
+    if (mDataLen > 0 && mData[mDataLen - 1].mIsStart)
+    {
+        stop();
+    }
+    if (kVerbose) SNPRINTF_OR_RETURN(*str, *size, "# Got %d samples for %s\n", mDataLen, mName);
+    processSamples();
+
+    SNPRINTF_OR_RETURN(*str, *size, "# StopWatch %s total/cumulative duration %f Samples: %d\n",
+                       mName, mDuration, mNum);
+    printThroughput(str, size);
+    printAverageMinMax(str, size);
+
+    if (printRaw)
+    {
+        // print comment header and summary values.
+
+        SNPRINTF_OR_RETURN(*str, *size, "# Name Iterations  Duration Min MinIdx Max MaxIdx SizeKbytes\n");
+        SNPRINTF_OR_RETURN(*str, *size, "%s %d %f %f %d %f %d %d\n", mName, mNum, mDuration,
+                           mMinDuration, mMinIdx, mMaxDuration, mMaxIdx, mSizeKbytes);
+        // print each duration sample
+        for (size_t i = 0; i < mDataLen / 2; ++i)
+        {
+            long second = mData[i * 2].mTime.tv_sec - mStart.tv_sec;
+            long nano = mData[i * 2].mTime.tv_nsec - mStart.tv_nsec;
+
+            SNPRINTF_OR_RETURN(*str, *size, "%f %f\n", double(second) + double(nano) / 1.0e9, mDeltas[i]);
+        }
+    }
+
+}
+
+// Normally we should have enough capacity but if we have to
+// reallocate the measurement buffer (e.g start and stop called more
+// than once in an iteration) we let the user know. She should provide
+// a capacity when building the StopWatch.
+void StopWatch::checkCapacity()
+{
+    if (mDataLen >= mCapacity)
+    {
+        mCapacity *= 2;
+        fprintf(stderr, "# Increased capacity to %d for %s. Measurement affected.\n",
+                mCapacity, mName);
+        mData = (Measurement *)realloc(mData, mCapacity * sizeof(Measurement));
+    }
+}
+
+
+// Go over all the samples and compute the diffs between a start and
+// stop pair. The diff is accumulated in mDuration and inserted in
+// mDeltas.
+// The min and max values for a diff are also tracked.
+void StopWatch::processSamples()
+{
+    if (kVerbose) fprintf(stderr, "processing samples\n");
+    size_t n = mDataLen / 2;
+    mDeltas= new double[n];
+    for (size_t i = 0; i < mDataLen; i += 2)   // even: start  odd: stop
+    {
+        long second = mData[i + 1].mTime.tv_sec - mData[i].mTime.tv_sec;
+        long nano = mData[i + 1].mTime.tv_nsec - mData[i].mTime.tv_nsec;
+
+        mDeltas[i / 2] = double(second) + double(nano) / 1.0e9;
+    }
+
+    for (size_t i = 0; i < n; ++i)
+    {
+        if (0 == i)
+        {
+            mMinDuration = mMaxDuration = mDeltas[i];
+        }
+        else
+        {
+            if (mMaxDuration < mDeltas[i])
+            {
+                mMaxDuration = mDeltas[i];
+                mMaxIdx = i;
+            }
+            if (mMinDuration > mDeltas[i])
+            {
+                mMinDuration = mDeltas[i];
+                mMinIdx = i;
+            }
+        }
+        mDuration += mDeltas[i];
+    }
+    double avgDuration = mDuration / n;
+    double diffSQ = 0.0;
+    for (size_t i = 0; i < n; ++i)
+    {
+      diffSQ += pow((mDeltas[i] - avgDuration), 2.0);
+    }
+    mDeviation = sqrt(diffSQ / n);
+}
+
+
+double StopWatch::timespecToDouble(const struct timespec& time)
+{
+    double val = double(time.tv_nsec) / 1.0e9 + double(time.tv_sec);
+    return val < 0.0 ? -val : val;  // sometimes 0.00 is -0.00
+}
+
+
+// If we have only 2 values, don't bother printing anything.
+void StopWatch::printAverageMinMax(char **str, size_t *size)
+{
+    if (mDataLen > 2) // if there is only one sample, avg, min, max are trivial.
+    {
+        SNPRINTF_OR_RETURN(*str, *size, "# Average %s duration %f s/op\n", mName, mDuration / mNum);
+        SNPRINTF_OR_RETURN(*str, *size, "# Standard deviation %s duration %f \n", mName, mDeviation);
+        SNPRINTF_OR_RETURN(*str, *size, "# Min %s duration %f [%d]\n", mName, mMinDuration, mMinIdx);
+        SNPRINTF_OR_RETURN(*str, *size, "# Max %s duration %f [%d]\n", mName, mMaxDuration, mMaxIdx);
+    }
+}
+
+void StopWatch::printThroughput(char **str, size_t *size)
+{
+    if (0 != mSizeKbytes)
+    {
+        SNPRINTF_OR_RETURN(*str, *size, "# Size: %d Kbytes  Total: %d\n", mSizeKbytes, mNum);
+        SNPRINTF_OR_RETURN(*str, *size, "# Speed %f Kbyte/s\n", double(mSizeKbytes) * mNum / mDuration);
+    }
+}
+}  // namespace android_test
diff --git a/tests/sdcard/stopwatch.h b/tests/sdcard/stopwatch.h
new file mode 100644
index 0000000..c54f257
--- /dev/null
+++ b/tests/sdcard/stopwatch.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE 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.
+ */
+
+#ifndef ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_STOPWATCH_H_
+#define ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_STOPWATCH_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+namespace android_test {
+
+// StopWatch class to collect execution statistics.
+//
+// Once the watch has been created, start and stop can be called to
+// capture an event duration.
+//
+// On completion, use 'sprint' to retrieve the data.
+//
+// If StopWatch::setPrintRawMode(true) has been called, the raw
+// samples also are printed.
+// The print method is thread safe to avoid mixing the result of
+// watches on different threads. For processes, use different files
+// that you concat after the run.
+//
+// If the time measure is associated with some volume of data, use
+// setMbytes, the print method will compute the average throughput
+// based on that value.
+//
+// To capture the time accurately and since the runs are not too long,
+// we collect the raw start and stop time in an array that get
+// processed once all the measurements have been done.
+//
+// Typical Usage:
+// ==============
+//
+//  StopWatch watch("my name", 20);
+//
+//  for (int i = 0; i < 20; ++i) {
+//    watch.start();
+//    doMyStuff();
+//    watch.stop();
+//  }
+//  char buffer[4096];
+//  char *str = buffer;
+//  size_t size = sizeof(buffer);
+//  watch.sprint(&str, &size);
+//
+
+class StopWatch {
+  public:
+    // Time of the snapshot and its nature (start of the interval or end of it).
+    struct Measurement {
+        struct timespec mTime;
+        bool mIsStart;
+    };
+    static const size_t kUseDefaultCapacity = 20;
+
+    // Create a stop watch. Default capacity == 2 * interval_nb
+    // @param name To be used when the results are displayed. No
+    //             spaces, use _ instead.
+    // @param capacity Hint about the number of sampless that will be
+    //                 measured (1 sample == 1 start + 1 stop). Used
+    //                 to size the internal storage, when the capacity
+    //                 is reached, it is doubled.
+    StopWatch(const char *name, size_t capacity = kUseDefaultCapacity);
+    ~StopWatch();
+
+    // A StopWatch instance measures time intervals. Use setDataSize
+    // if some volume of data is processed during these intervals, to
+    // get the average throughput (in kbytes/s) printed.
+    void setDataSize(size_t size_in_bytes) { mSizeKbytes = size_in_bytes / 1000; }
+
+    // Starts and stops the timer. The time between the 2 calls is an
+    // interval whose duration will be reported in sprint.
+    void start();
+    void stop();
+
+    // Print a summary of the measurement and optionaly the raw data.
+    // The summary is commented out using a leading '#'.  The raw data
+    // is a pair (time, duration). The 1st sample is always at time
+    // '0.0'.
+    // @param str[inout] On entry points to the begining of a buffer
+    // where to write the data. On exit points pass the last byte
+    // written.
+    // @param size[inout] On entry points to the size of the buffer
+    // pointed by *str. On exit *size is the amount of free space left
+    // in the buffer. If there was not enough space the data is truncated
+    // and a warning is printed.
+    void sprint(char **str, size_t *size);
+
+    // @return true if at least one interval was timed.
+    bool used() const { return mUsed; }
+
+    // Affects all the timers. Instructs all the timers to print the
+    // raw data as well as the summary.
+    static void setPrintRawMode(bool printRaw);
+
+  private:
+    void checkCapacity();
+    double timespecToDouble(const struct timespec& time);
+    void printAverageMinMax(char **str, size_t *size);
+    void printThroughput(char **str, size_t *size);
+    // Allocate mDeltas and fill it in. Search for the min and max.
+    void processSamples();
+
+    char *const mName;  // Name of the test.
+    struct timespec mStart;
+    size_t mNum; // # of intervals == # of start() calls.
+    struct Measurement *mData;
+    size_t mDataLen;
+    size_t mCapacity;
+    int mSizeKbytes;
+
+    bool mAlreadyPrinted;
+    bool mPrintRaw;
+
+    double mDuration;
+    double mDeviation;
+    double mMinDuration;
+    size_t mMinIdx;
+    double mMaxDuration;
+    size_t mMaxIdx;
+    double *mDeltas;
+
+    bool mUsed;
+};
+
+}  // namespace android_test
+
+#endif  // ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_STOPWATCH_H_
diff --git a/tests/sdcard/sysutil.cpp b/tests/sdcard/sysutil.cpp
new file mode 100644
index 0000000..0182590
--- /dev/null
+++ b/tests/sdcard/sysutil.cpp
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE 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.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "sysutil.h"
+
+namespace {
+const int kError = -1;
+// Max number of retries on EAGAIN and EINTR. Totally arbitrary.
+const int kMaxAttempts = 8;
+
+// How long to wait after a cache purge. A few seconds (arbitrary).
+const int kCachePurgeSleepDuration = 2; // seconds
+
+const bool kSilentIfMissing = false;
+
+const char *kKernelVersion = "/proc/version";
+const char *kScalingGovernorFormat = "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor";
+const char *kDropCaches = "/proc/sys/vm/drop_caches";
+const char *kSchedFeatures = "/sys/kernel/debug/sched_features";
+const char *kNewFairSleepers = "NEW_FAIR_SLEEPERS";
+const char *kNoNewFairSleepers = "NO_NEW_FAIR_SLEEPERS";
+const char *kNormalizedSleepers = "NORMALIZED_SLEEPER"; // no 's' at the end
+const char *kNoNormalizedSleepers = "NO_NORMALIZED_SLEEPER";
+
+const char *kDebugfsWarningMsg = "Did you 'adb root; adb shell mount -t debugfs none /sys/kernel/debug' ?";
+
+// TODO: Surely these file utility functions must exist already. A
+// quick grep did not turn up anything. Look harder later.
+
+void printErrno(const char *msg, const char *filename)
+{
+    fprintf(stderr, "# %s %s %d %s\n", msg, filename, errno, strerror(errno));
+}
+
+// Read a C-string from a file.  If the buffer is too short, an error
+// message will be printed on stderr.
+// @param filename Of the file to read.
+// @param start    Buffer where the data should be written to.
+// @param size     The size of the buffer pointed by str. Must be >= 1.
+// @return The number of characters read (not including the trailing'\0' used
+//         to end the string) or -1 if there was an error.
+int readStringFromFile(const char *filename, char *const start, size_t size, bool must_exist=true)
+{
+    if (NULL == start || size == 0)
+    {
+        return 0;
+    }
+    char *end = start;
+    int fd = open(filename, O_RDONLY);
+
+    if (fd < 0)
+    {
+        if (ENOENT != errno || must_exist)
+        {
+            printErrno("Failed to open", filename);
+        }
+        return kError;
+    }
+
+    bool eof = false;
+    bool error = false;
+    int attempts = 0;
+
+    --size; // reserve space for trailing '\0'
+
+    while (size > 0 && !error && !eof && attempts < kMaxAttempts)
+    {
+        ssize_t s;
+
+        s = read(fd, end, size);
+
+        if (s < 0)
+        {
+            error = EAGAIN != errno && EINTR != errno;
+            if (error)
+            {
+                printErrno("Failed to read", filename);
+            }
+        }
+        else if (0 == s)
+        {
+            eof = true;
+        }
+        else
+        {
+            end += s;
+            size -= s;
+        }
+        ++attempts;
+    }
+
+    close(fd);
+
+    if (error)
+    {
+        return kError;
+    }
+    else
+    {
+        *end = '\0';
+        if (!eof)
+        {
+            fprintf(stderr, "Buffer too small for %s\n", filename);
+        }
+        return end - start;
+    }
+}
+
+// Write a C string ('\0' terminated) to a file.
+//
+int writeStringToFile(const char *filename, const char *start, bool must_exist=true)
+{
+    int fd = open(filename, O_WRONLY);
+
+
+    if (fd < 0)
+    {
+        if (ENOENT != errno || must_exist)
+        {
+            printErrno("Failed to open", filename);
+        }
+        return kError;
+    }
+
+    const size_t len = strlen(start);
+    size_t size = len;
+    bool error = false;
+    int attempts = 0;
+
+    while (size > 0 && !error && attempts < kMaxAttempts)
+    {
+        ssize_t s = write(fd, start, size);
+
+        if (s < 0)
+        {
+            error = EAGAIN != errno && EINTR != errno;
+            if (error)
+            {
+                printErrno("Failed to write", filename);
+            }
+        }
+        else
+        {
+            start += s;
+            size -= s;
+        }
+        ++attempts;
+    }
+    close(fd);
+
+    if (error)
+    {
+        return kError;
+    }
+    else
+    {
+        if (size > 0)
+        {
+            fprintf(stderr, "Partial write to %s (%d out of %d)\n",
+                    filename, size, len);
+        }
+        return len - size;
+    }
+}
+
+int writeIntToFile(const char *filename, long value)
+{
+    char buffer[16] = {0,};
+    sprintf(buffer, "%ld", value);
+    return writeStringToFile(filename, buffer);
+}
+
+// @return a message describing the reason why the child exited. The
+// message is in a shared buffer, not thread safe, erased by
+// subsequent calls.
+const char *reasonChildExited(int status)
+{
+    static char buffer[80];
+
+    if (WIFEXITED(status))
+    {
+        snprintf(buffer, sizeof(buffer), "ok (%d)",  WEXITSTATUS(status));
+    }
+    else if (WIFSIGNALED(status))
+    {
+        snprintf(buffer, sizeof(buffer), "signaled (%d %s)",  WTERMSIG(status), strsignal(WTERMSIG(status)));
+    }
+    else
+    {
+        snprintf(buffer, sizeof(buffer), "stopped?");
+    }
+    return buffer;
+}
+
+
+}  // anonymous namespace
+
+namespace android {
+
+int kernelVersion(char *str, size_t size)
+{
+    return readStringFromFile(kKernelVersion, str, size);
+}
+
+int pidOutOfMemoryAdj()
+{
+    char filename[FILENAME_MAX];
+
+    snprintf(filename, sizeof(filename), "/proc/%d/oom_adj", getpid());
+
+    char value[16];
+    if (readStringFromFile(filename, value, sizeof(value)) == -1)
+    {
+        return -127;
+    }
+    else
+    {
+        return atoi(value);
+    }
+}
+
+void setPidOutOfMemoryAdj(int level)
+{
+    char filename[FILENAME_MAX];
+
+    snprintf(filename, sizeof(filename), "/proc/%d/oom_adj", getpid());
+    writeIntToFile(filename, level);
+}
+
+void disableCpuScaling()
+{
+    for (int cpu = 0; cpu < 16; ++cpu) // 16 cores mobile phones, abestos pockets recommended.
+    {
+        char governor[FILENAME_MAX];
+        sprintf(governor, kScalingGovernorFormat, cpu);
+
+        if (writeStringToFile(governor, "performance", kSilentIfMissing) < 0)
+        {
+            if (cpu > 0 && errno == ENOENT)
+            {
+                break;  // cpu1 or above not found, ok since we have cpu0.
+            }
+            fprintf(stderr, "Failed to write to scaling governor file for cpu %d: %d %s",
+                    cpu, errno, strerror(errno));
+            break;
+        }
+    }
+}
+
+int schedFeatures(char *str, size_t size)
+{
+    return readStringFromFile(kSchedFeatures, str, size);
+}
+
+bool newFairSleepers()
+{
+    char value[256] = {0,};
+
+    if (readStringFromFile(kSchedFeatures, value, sizeof(value)) == -1)
+    {
+        printErrno(kDebugfsWarningMsg, kSchedFeatures);
+        return false;
+    }
+    return strstr(value, "NO_NEW_FAIR_SLEEPERS") == NULL;
+}
+
+void setNewFairSleepers(bool on)
+{
+    int retcode;
+
+    if (on)
+    {
+        retcode = writeStringToFile(kSchedFeatures, kNewFairSleepers);
+    }
+    else
+    {
+        retcode = writeStringToFile(kSchedFeatures, kNoNewFairSleepers);
+    }
+    if (retcode < 0)
+    {
+        fprintf(stderr, "# %s\n", kDebugfsWarningMsg);
+    }
+}
+
+bool normalizedSleepers()
+{
+    char value[256] = {0,};
+
+    if (readStringFromFile(kSchedFeatures, value, sizeof(value)) == -1)
+    {
+        printErrno(kDebugfsWarningMsg, kSchedFeatures);
+        return false;
+    }
+    return strstr(value, "NO_NEW_FAIR_SLEEPERS") == NULL;
+}
+
+void setNormalizedSleepers(bool on)
+{
+    int retcode;
+
+    if (on)
+    {
+        retcode = writeStringToFile(kSchedFeatures, kNormalizedSleepers);
+    }
+    else
+    {
+        retcode = writeStringToFile(kSchedFeatures, kNoNormalizedSleepers);
+    }
+    if (retcode < 0)
+    {
+        fprintf(stderr, "# %s\n", kDebugfsWarningMsg);
+    }
+}
+
+pid_t forkOrExit()
+{
+    pid_t childpid = fork();
+
+    if (-1 == childpid)
+    {
+        fprintf(stderr, "Fork failed: %d %s", errno, strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+    return childpid;
+}
+
+void waitForChildrenOrExit(int num)
+{
+    while (num > 0)
+    {
+        int status;
+        pid_t pid = wait(&status);
+        if (-1 == pid)
+        {
+            fprintf(stderr, "Wait failed\n");
+        }
+        else
+        {
+            if (!WIFEXITED(status))
+            {
+                fprintf(stderr, "Child pid %d did not exit cleanly %s\n",
+                        pid, reasonChildExited(status));
+                exit(EXIT_FAILURE);
+            }
+        }
+        --num;
+    }
+}
+
+// Sync and cache cleaning functions.  In the old hpux days I was told
+// to always call *sync twice. The same advice seems to be still true
+// today so *sync is called twice.
+// Also we wait 'a little' to give a chance to background threads to
+// purge their caches.
+void syncAndDropCaches(int code)
+{
+    sync();
+    sync();
+    writeIntToFile(kDropCaches, code);
+    sleep(kCachePurgeSleepDuration);
+}
+
+
+void fsyncAndDropCaches(int fd, int code)
+{
+    fsync(fd);
+    fsync(fd);
+    writeIntToFile(kDropCaches, code);
+    sleep(kCachePurgeSleepDuration);
+}
+
+
+void resetDirectory(const char *directory)
+{
+    DIR *dir = opendir(directory);
+
+    if (NULL != dir)
+    {
+        struct dirent *entry;
+        char name_buffer[PATH_MAX];
+
+        while((entry = readdir(dir)))
+        {
+            if (0 == strcmp(entry->d_name, ".")
+                || 0 == strcmp(entry->d_name, "..")
+                || 0 == strcmp(entry->d_name, "lost+found"))
+            {
+                continue;
+            }
+            strcpy(name_buffer, directory);
+            strcat(name_buffer, "/");
+            strcat(name_buffer, entry->d_name);
+            unlink(name_buffer);
+        }
+        closedir(dir);
+    } else {
+        mkdir(directory, S_IRWXU);
+    }
+}
+
+
+// IPC
+bool writePidAndWaitForReply(int writefd, int readfd)
+{
+    if (writefd > readfd)
+    {
+        fprintf(stderr, "Called with args in wrong order!!\n");
+        return false;
+    }
+    pid_t pid = getpid();
+    char *start = reinterpret_cast<char *>(&pid);
+    size_t size = sizeof(pid);
+    bool error = false;
+    int attempts = 0;
+
+    while (size > 0 && !error && attempts < kMaxAttempts)
+    {
+        ssize_t s = write(writefd, start, size);
+
+        if (s < 0)
+        {
+            error = EAGAIN != errno && EINTR != errno;
+            if (error)
+            {
+                printErrno("Failed to write", "parent");
+            }
+        }
+        else
+        {
+            start += s;
+            size -= s;
+        }
+        ++attempts;
+    }
+
+    if (error || 0 != size)
+    {
+        return false;
+    }
+
+    bool eof = false;
+    char dummy;
+    size = sizeof(dummy);
+    error = false;
+    attempts = 0;
+
+    while (size > 0 && !error && !eof && attempts < kMaxAttempts)
+    {
+        ssize_t s;
+
+        s = read(readfd, &dummy, size);
+
+        if (s < 0)
+        {
+            error = EAGAIN != errno && EINTR != errno;
+            if (error)
+            {
+                printErrno("Failed to read", "parent");
+            }
+        }
+        else if (0 == s)
+        {
+            eof = true;
+        }
+        else
+        {
+            size -= s;
+        }
+        ++attempts;
+    }
+    if (error || 0 != size)
+    {
+        return false;
+    }
+    return true;
+}
+
+
+
+bool waitForChildrenAndSignal(int mProcessNb, int readfd, int writefd)
+{
+    if (readfd > writefd)
+    {
+        fprintf(stderr, "Called with args in wrong order!!\n");
+        return false;
+    }
+
+    bool error;
+    int attempts;
+    size_t size;
+
+    for (int p = 0; p < mProcessNb; ++p)
+    {
+        bool eof = false;
+        pid_t pid;
+        char *end = reinterpret_cast<char *>(&pid);
+
+        error = false;
+        attempts = 0;
+        size = sizeof(pid);
+
+        while (size > 0 && !error && !eof && attempts < kMaxAttempts)
+        {
+            ssize_t s;
+
+            s = read(readfd, end, size);
+
+            if (s < 0)
+            {
+                error = EAGAIN != errno && EINTR != errno;
+                if (error)
+                {
+                    printErrno("Failed to read", "child");
+                }
+            }
+            else if (0 == s)
+            {
+                eof = true;
+            }
+            else
+            {
+                end += s;
+                size -= s;
+            }
+            ++attempts;
+        }
+
+        if (error || 0 != size)
+        {
+            return false;
+        }
+    }
+
+    for (int p = 0; p < mProcessNb; ++p)
+    {
+        char dummy;
+
+        error = false;
+        attempts = 0;
+        size = sizeof(dummy);
+
+        while (size > 0 && !error && attempts < kMaxAttempts)
+        {
+            ssize_t s = write(writefd, &dummy, size);
+
+            if (s < 0)
+            {
+                error = EAGAIN != errno && EINTR != errno;
+                if (error)
+                {
+                    printErrno("Failed to write", "child");
+                }
+            }
+            else
+            {
+                size -= s;
+            }
+            ++attempts;
+        }
+
+        if (error || 0 != size)
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+}  // namespace android
diff --git a/tests/sdcard/sysutil.h b/tests/sdcard/sysutil.h
new file mode 100644
index 0000000..3df79c1
--- /dev/null
+++ b/tests/sdcard/sysutil.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE 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.
+ */
+
+#ifndef ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_SYSUTIL_H_
+#define ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_SYSUTIL_H_
+
+#include <stdlib.h>
+namespace android {
+
+// Collection of functions to access the system:
+// .kernelVersion         Retrieve the full kernel description.
+// .pidOutOfMemoryAdj     Get and set the OOM adj value.
+// .setPidOutOfMemoryAdj
+// .schedFeatures         Manipulate the scheduler using debugfs.
+// .newFairSleepers
+// .setNewFairSleepers
+// .disableCpuScaling     Set cpu scaling to 'performance'.
+// .forkOrExit            Fork a child or exit.
+// .syncAnddropCaches     Call sync an drop page/dentries/inodes caches.
+// .fsyncAnddropCaches    Call fsync an drop page/dentries/inodes caches.
+// .resetDirectory        Delete (non-recursive) files in a directory.
+//
+// IPC function to synchonize a processes with their parent.
+// .writePidAndWaitForReply To instruct the parent the child is ready.
+//                          Blocks until the parent signals back.
+// .waitForChildrenAndSignal Blocks until all the children have called
+//                           writePidAndWaitForReply.
+//                           Then unblock all the children.
+// .waitForChildrenOrExit Wait and exit if a child exit with errors.
+//
+
+// Minimum size for the buffer to retrieve the kernel version.
+static const size_t kMinKernelVersionBufferSize = 256;
+
+// @param str points to the buffer where the kernel version should be
+//            added. Must be at least kMinKernelVersionBufferSize chars.
+// @param size of the buffer pointed by str.
+// @return If successful the number of characters inserted in the
+//         buffer (not including the trailing '\0' byte). -1 otherwise.
+int kernelVersion(char *str, size_t size);
+
+
+// Return the out of memory adj for this process. /proc/<pid>/oom_adj.
+// @return the oom_adj of the current process. Typically:
+//           0: a regular process. Should die on OOM.
+//         -16: system_server level.
+//         -17: disable, this process  will never be killed.
+//        -127: error.
+int pidOutOfMemoryAdj();
+void setPidOutOfMemoryAdj(int level);
+
+// Disable cpu scaling.
+void disableCpuScaling();
+
+
+// Minimum size for the buffer to retrieve the sched features.
+static const size_t kMinSchedFeaturesBufferSize = 256;
+
+// @param str points to the buffer where the sched features should be
+//            added. Must be at least kMinSchedFeaturesBufferSize chars.
+// @param size of the buffer pointed by str.
+// @return If successful the number of characters inserted in the
+//         buffer (not including the trailing '\0' byte). -1 otherwise.
+int schedFeatures(char *str, size_t size);
+
+// @return true if NEW_FAIR_SLEEPERS is set, false if NO_NEW_FAIR_SLEEPERS is set.
+bool newFairSleepers();
+
+// Turns NEW_FAIR_SLEEPERS on or off.
+void setNewFairSleepers(bool on);
+
+// @return true if NORMALIZED_SLEEPERS is set, false if NO_NORMALIZED_SLEEPERS is set.
+bool normalizedSleepers();
+
+// Turns NORMALIZED_SLEEPERS on or off.
+void setNormalizedSleepers(bool on);
+
+// Filesystem
+
+// Sync and drop caches. Sync is needed because dirty objects are not
+// freable.
+// @param code:
+//        * 1 To free pagecache.
+//        * 2 To free dentries and inodes.
+//        * 3 To free pagecache, dentries and inodes.
+void syncAndDropCaches(int code = 3);
+
+// Fsync the given fd and drop caches. Fsync is needed because dirty
+// objects are not freable.
+// @param code:
+//        * 1 To free pagecache.
+//        * 2 To free dentries and inodes.
+//        * 3 To free pagecache, dentries and inodes.
+void fsyncAndDropCaches(int fd, int code = 3);
+
+// Delete all the files in the given directory.  If the directory does
+// not exist, it is created.  Use this at the beginning of a test to
+// make sure you have a clean existing directory, previous run may
+// have crashed and left clutter around.
+void resetDirectory(const char *directory);
+
+// IPC
+
+// Try to fork. exit on failure.
+pid_t forkOrExit();
+
+// Signal our parent we are alive and ready by sending our pid.
+// Then do a blocking read for parent's reply.
+bool writePidAndWaitForReply(int writefd, int readfd);
+
+// Wait for all the children to report their pids.
+// Then unblock them.
+bool waitForChildrenAndSignal(int mProcessNb, int readfd, int writefd);
+
+// Wait for 'num' children to complete.
+// If a child did not exit cleanly, exit.
+void waitForChildrenOrExit(int num);
+
+}  // namespace android
+
+#endif  // ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_SYSUTIL_H_
diff --git a/tests/sdcard/testcase.cpp b/tests/sdcard/testcase.cpp
new file mode 100644
index 0000000..06fd71b
--- /dev/null
+++ b/tests/sdcard/testcase.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE 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.
+ */
+
+#include "testcase.h"
+#include <hardware_legacy/power.h>  // wake lock
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <linux/fadvise.h>
+
+namespace {
+const bool kVerbose = false;
+}
+
+namespace android_test {
+
+TestCase::TestCase(const char *appName)
+    : mTestBody(NULL), mAppName(appName), mDataSize(1000 * 1000),
+      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)
+{
+    // Make sure the cpu and phone are fully awake. The
+    // FULL_WAKE_LOCK was used by java apps and don't do
+    // anything. Also the partial wake lock is a nop if the phone
+    // is plugged in via USB.
+    acquire_wake_lock(PARTIAL_WAKE_LOCK, mAppName);
+    mPid = getpid();
+    setNewFairSleepers(true);
+    setNormalizedSleepers(true);
+    if (pipe(mIpc) < 0)
+    {
+        fprintf(stderr, "pipe failed\n");
+        exit(1);
+    }
+    if (pipe(mIpc + 2) < 0)
+    {
+        fprintf(stderr, "pipe failed\n");
+        exit(1);
+    }
+}
+
+TestCase::~TestCase()
+{
+    release_wake_lock(mAppName);
+    for (int i = 0; i < 4; ++i) close(mIpc[i]);
+    delete mTestTimer;
+    delete mOpenTimer;
+}
+
+
+bool TestCase::runTest()
+{
+    if (UNKNOWN_TEST == mType)
+    {
+        fprintf(stderr, "No test set.");
+        return false;
+    }
+    for (size_t p = 0; p < mNproc; ++p)
+    {
+        pid_t childpid = android::forkOrExit();
+
+        if (0 == childpid) { // I am a child, run the test.
+            mPid = getpid();
+            close(mIpc[READ_FROM_CHILD]);
+            close(mIpc[WRITE_TO_CHILD]);
+
+            if (kVerbose) printf("Child pid: %d\n", mPid);
+            if (!mTestBody(this)) {
+                printf("Test failed\n");
+            }
+            char buffer[32000] = {0,};
+            char *str = buffer;
+            size_t size_left = sizeof(buffer);
+
+            testTimer()->sprint(&str, &size_left);
+            if(openTimer()->used()) openTimer()->sprint(&str, &size_left);
+            if(readTimer()->used()) readTimer()->sprint(&str, &size_left);
+            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);
+
+
+            close(mIpc[WRITE_TO_PARENT]);
+            close(mIpc[READ_FROM_PARENT]);
+            exit(EXIT_SUCCESS);
+        }
+    }
+    // I am the parent process
+    close(mIpc[WRITE_TO_PARENT]);
+    close(mIpc[READ_FROM_PARENT]);
+
+    // Block until all the children have reported for
+    // duty. Unblock them so they start the work.
+    if (!android::waitForChildrenAndSignal(mNproc, mIpc[READ_FROM_CHILD], mIpc[WRITE_TO_CHILD]))
+    {
+        exit(1);
+    }
+
+    // Process the output of each child.
+    // TODO: handle EINTR
+    char buffer[32000] = {0,};
+    while(read(mIpc[READ_FROM_CHILD], buffer, sizeof(buffer)) != 0)
+    {
+        printf("%s", buffer);
+        fflush(stdout);
+        memset(buffer, 0, sizeof(buffer));
+    }
+    // Parent is waiting for children to exit.
+    android::waitForChildrenOrExit(mNproc);
+    return true;
+}
+
+void TestCase::setIter(size_t iter)
+{
+    mIter = iter;
+}
+
+void TestCase::createTimers()
+{
+    char total_time[80];
+
+    snprintf(total_time, sizeof(total_time), "%s_total", mName);
+    mTestTimer = new StopWatch(total_time, 1);
+    mTestTimer->setDataSize(dataSize());
+
+    mOpenTimer = new StopWatch("open", iter() * kReadWriteFactor);
+
+    mReadTimer = new StopWatch("read", iter() * dataSize() / chunkSize() * kReadWriteFactor);
+    mReadTimer->setDataSize(dataSize());
+
+    mWriteTimer = new StopWatch("write", iter() * dataSize() / chunkSize());
+    mWriteTimer->setDataSize(dataSize());
+
+    mSyncTimer = new StopWatch("sync", iter());
+
+    mTruncateTimer = new StopWatch("truncate", iter());
+
+    mTraverseTimer = new StopWatch("traversal", iter());
+}
+
+bool TestCase::setTypeFromName(const char *test_name)
+{
+    strcpy(mName, test_name);
+    if (strcmp(mName, "write") == 0) mType = WRITE;
+    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;
+}
+
+void TestCase::setSync(Sync s)
+{
+    mSync = s;
+}
+
+const char *TestCase::syncAsStr() const
+{
+    return mSync == NO_SYNC ? "disabled" : (mSync == FSYNC ? "fsync" : "sync");
+}
+
+void TestCase::setFadvise(const char *advice)
+{
+    mFadvice = POSIX_FADV_NORMAL;
+    if (strcmp(advice, "sequential") == 0)
+    {
+        mFadvice = POSIX_FADV_SEQUENTIAL;
+    }
+    else if (strcmp(advice, "random") == 0)
+    {
+        mFadvice = POSIX_FADV_RANDOM;
+    }
+    else if (strcmp(advice, "noreuse") == 0)
+    {
+        mFadvice = POSIX_FADV_NOREUSE;
+    }
+    else if (strcmp(advice, "willneed") == 0)
+    {
+        mFadvice = POSIX_FADV_WILLNEED;
+    }
+    else if (strcmp(advice, "dontneed") == 0)
+    {
+        mFadvice = POSIX_FADV_DONTNEED;
+    }
+}
+
+const char *TestCase::fadviseAsStr() const
+{
+    switch (mFadvice) {
+        case POSIX_FADV_NORMAL: return "fadv_normal";
+        case POSIX_FADV_SEQUENTIAL: return "fadv_sequential";
+        case POSIX_FADV_RANDOM: return "fadv_random";
+        case POSIX_FADV_NOREUSE: return "fadv_noreuse";
+        case POSIX_FADV_WILLNEED: return "fadv_willneed";
+        case POSIX_FADV_DONTNEED: return "fadv_dontneed";
+        default: return "fadvice_unknown";
+    }
+}
+
+
+}  // namespace android_test
diff --git a/tests/sdcard/testcase.h b/tests/sdcard/testcase.h
new file mode 100644
index 0000000..e973d9a
--- /dev/null
+++ b/tests/sdcard/testcase.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE 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.
+ */
+
+
+#ifndef SYSTEM_EXTRAS_TESTS_SDCARD_TESTCASE_H_
+#define SYSTEM_EXTRAS_TESTS_SDCARD_TESTCASE_H_
+
+#include <stdlib.h>
+#include "stopwatch.h"
+#include "sysutil.h"
+
+namespace android_test {
+
+// Class to group test parameters and implementation.
+// Takes care of forking child processes and wait for them.
+
+class TestCase {
+  public:
+    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};
+
+    // Reads takes less time than writes. This is a basic
+    // approximation of how much longer the read tasks must run to
+    // terminate roughly at the same time as the write tasks.
+    const static int kReadWriteFactor = 5;
+
+    TestCase(const char *appName);
+
+    ~TestCase();
+
+    size_t iter() const { return mIter; }
+    void setIter(size_t iter);
+
+    size_t nproc() const { return mNproc; }
+    void setNproc(size_t val) { mNproc = val; }
+
+    size_t dataSize() const { return mDataSize; }
+    void setDataSize(size_t val) { mDataSize = val; }
+
+    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;
+        android::setNewFairSleepers(val);
+    }
+
+    bool normalizedSleepers() const { return mNormalizedSleepers; }
+    void setNormalizedSleepers(bool val) {
+        mNormalizedSleepers = val;
+        android::setNormalizedSleepers(val);
+    }
+
+    Sync sync() const { return mSync; }
+    void setSync(Sync s);
+    const char *syncAsStr() const;
+
+    bool cpuScaling() const { return mCpuScaling; }
+    void setCpuScaling() { mCpuScaling = true; }
+
+    bool truncateToSize() const { return mTruncateToSize; }
+    void setTruncateToSize() { mTruncateToSize = true; }
+
+    int fadvise() { return mFadvice; }
+    void setFadvise(const char *advice);
+    const char *fadviseAsStr() const;
+
+    // Print the samples.
+    void setDump() { StopWatch::setPrintRawMode(true); }
+
+    StopWatch *testTimer() { return mTestTimer; }
+    StopWatch *openTimer() { return mOpenTimer; }
+    StopWatch *readTimer() { return mReadTimer; }
+    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();
+
+    void signalParentAndWait() {
+        if (!android::writePidAndWaitForReply(mIpc[WRITE_TO_PARENT], mIpc[READ_FROM_PARENT])) {
+            exit(1);
+        }
+    }
+
+    void createTimers();
+    bool setTypeFromName(const char *test_name);
+    Type type() const { return mType; }
+    pid_t pid() const { return mPid; }
+    const char *name() const { return mName; }
+
+    // This is set to the function that will actually do the test when
+    // the command line arguments have been parsed. The function will
+    // be run in one or more child(ren) process(es).
+    bool (*mTestBody)(TestCase *);
+private:
+    const char *mAppName;
+    size_t mDataSize;
+    size_t mChunkSize;
+    size_t mTreeDepth;
+    size_t mIter;
+    size_t mNproc;
+    pid_t mPid;
+    char mName[80];
+    Type mType;
+
+    bool mDump;  // print the raw values instead of a human friendly report.
+    bool mCpuScaling;  // true, do not turn off cpu scaling.
+    Sync mSync;
+    int mFadvice;
+    // When new files are created, truncate them to the final size.
+    bool mTruncateToSize;
+
+    bool mNewFairSleepers;
+    bool mNormalizedSleepers;
+
+    // IPC
+    //        Parent               Child(ren)
+    // ---------------------------------------
+    // 0: read from child          closed
+    // 1: closed                   write to parent
+    // 2: closed                   read from parent
+    // 3: write to child           closed
+    int mIpc[4];
+
+    StopWatch *mTestTimer;  // Used to time the test overall.
+    StopWatch *mOpenTimer;  // Used to time the open calls.
+    StopWatch *mReadTimer;  // Used to time the read calls.
+    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
+
+#endif  // SYSTEM_EXTRAS_TESTS_SDCARD_TESTCASE_H_
diff --git a/tests/storage/Android.mk b/tests/storage/Android.mk
new file mode 100644
index 0000000..462ebef
--- /dev/null
+++ b/tests/storage/Android.mk
@@ -0,0 +1,17 @@
+# Copyright 2013 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := opentest.c
+LOCAL_MODULE := opentest
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES   := wipe_blkdev.c
+LOCAL_MODULE      := wipe_blkdev
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
diff --git a/tests/storage/opentest.c b/tests/storage/opentest.c
new file mode 100644
index 0000000..05d5586
--- /dev/null
+++ b/tests/storage/opentest.c
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int main(int argc, char *argv[])
+{
+    int i;
+    int nfiles;
+    int *fds;
+    char *dir;
+    struct stat statbuf;
+    char name[16];
+    struct rlimit rlim;
+
+    if (argc != 3) {
+        fprintf(stderr, "Usage: opentest <directory> <num_files>\n");
+        exit(1);
+    }
+
+    dir = argv[1];
+
+    nfiles = atoi(argv[2]);
+    if ((nfiles <= 0) || (nfiles > 65536)) {
+        fprintf(stderr, "num_files must be between 1 and 65536\n");
+        exit(1);
+    }
+
+    if (stat(dir, &statbuf)) {
+        fprintf(stderr, "Cannot stat %s\n", dir);
+        exit(1);
+    }
+
+    if (! S_ISDIR(statbuf.st_mode)) {
+        fprintf(stderr, "%s is not a directory!\n", dir);
+        exit(1);
+    }
+
+    if (access(dir, R_OK | W_OK)) {
+        fprintf(stderr, "No access to %s\n", dir);
+        exit(1);
+    }
+
+    fds = malloc(nfiles * sizeof(int));
+    if (fds == 0) {
+        fprintf(stderr, "Unable to malloc array of %d fds\n", nfiles);
+        exit(1);
+    }
+
+    if (chdir(dir)) {
+        fprintf(stderr, "Cannot chdir to %s\n", dir);
+        exit(1);
+    }
+
+    rlim.rlim_cur = nfiles + 10;
+    rlim.rlim_max = nfiles + 10;
+    if (setrlimit(RLIMIT_NOFILE, &rlim)) {
+        fprintf(stderr, "Unable to raise RLIMIT_NOFILE to %ld\n", rlim.rlim_cur);
+        exit(1);
+    }
+
+    for (i = 0; i < nfiles; i++) {
+        snprintf(name, sizeof(name), "%d", i);
+        fds[i] = open(name, O_WRONLY | O_CREAT, 0666);
+        if (fds[i] < 0) {
+            fprintf(stderr, "Unable to open %d fd\n", i);
+            exit(1);
+        }
+    }
+
+    /* Rely upon exit to cleanup! */
+    exit(0);
+}
+
+
diff --git a/tests/storage/wipe_blkdev.c b/tests/storage/wipe_blkdev.c
new file mode 100644
index 0000000..3cca7d2
--- /dev/null
+++ b/tests/storage/wipe_blkdev.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011, 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <errno.h>
+
+typedef unsigned long long u64;
+
+#ifndef BLKDISCARD
+#define BLKDISCARD _IO(0x12,119)
+#endif
+
+#ifndef BLKSECDISCARD
+#define BLKSECDISCARD _IO(0x12,125)
+#endif
+
+static u64 get_block_device_size(int fd)
+{
+        u64 size = 0;
+        int ret;
+
+        ret = ioctl(fd, BLKGETSIZE64, &size);
+
+        if (ret)
+                return 0;
+
+        return size;
+}
+
+static int wipe_block_device(int fd, u64 len, int secure)
+{
+    u64 range[2];
+    int ret;
+    int req;
+
+    range[0] = 0;
+    range[1] = len;
+    if (secure) {
+       req = BLKSECDISCARD;
+    } else {
+       req = BLKDISCARD;
+    }
+
+    ret = ioctl(fd, req, &range);
+    if (ret < 0) {
+        fprintf(stderr, "%s discard failed, errno = %d\n",
+                secure ? "Secure" : "Nonsecure", errno);
+    }
+
+    return ret;
+}
+
+static void usage(void)
+{
+    fprintf(stderr, "Usage: wipe_blkdev [-s] <partition>\n");
+    exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+    int secure = 0;
+    char *devname;
+    int fd;
+    u64 len;
+    struct stat statbuf;
+    int ret;
+
+    if ((argc != 2) && (argc != 3)) {
+        usage();
+    }
+
+    if (argc == 3) {
+        if (!strcmp(argv[1], "-s")) {
+            secure = 1;
+            devname = argv[2];
+        } else {
+            usage();
+        }
+    } else {
+        devname = argv[1];
+    }
+
+    fd = open(devname, O_RDWR);
+    if (fd < 0) {
+        fprintf(stderr, "Cannot open device %s\n", devname);
+        exit(1);
+    }
+
+    if (fstat(fd, &statbuf) < 0) {
+        fprintf(stderr, "Cannot stat %s\n", devname);
+        exit(1);
+    }
+
+    if (!S_ISBLK(statbuf.st_mode)) {
+        fprintf(stderr, "%s is not a block device\n", devname);
+        exit(1);
+    }
+
+    len = get_block_device_size(fd);
+
+    if (! len) {
+        fprintf(stderr, "Cannot get size of block device %s\n", devname);
+        exit(1);
+    }
+
+    ret = wipe_block_device(fd, len, secure);
+
+    close(fd);
+
+    return ret;
+}
diff --git a/tests/suspend_stress/Android.mk b/tests/suspend_stress/Android.mk
new file mode 100644
index 0000000..952f50f
--- /dev/null
+++ b/tests/suspend_stress/Android.mk
@@ -0,0 +1,9 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := suspend_stress.cpp
+LOCAL_MODULE := suspend_stress
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := libc libcutils
+include $(BUILD_EXECUTABLE)
diff --git a/tests/suspend_stress/suspend_stress.cpp b/tests/suspend_stress/suspend_stress.cpp
new file mode 100644
index 0000000..517581c
--- /dev/null
+++ b/tests/suspend_stress/suspend_stress.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+
+#include <cutils/klog.h>
+
+#define NSEC_PER_SEC (1000*1000*1000)
+#define MSEC_PER_SEC 1000
+#define NSEC_PER_MSEC (NSEC_PER_SEC/MSEC_PER_SEC)
+
+long long timediff_ns(const struct timespec *a, const struct timespec *b) {
+    return ((long long)(a->tv_sec - b->tv_sec)) * NSEC_PER_SEC +
+            (a->tv_nsec - b->tv_nsec);
+}
+
+void usage(void)
+{
+    printf("usage: suspend_stress [ <options> ]\n"
+           "options:\n"
+           "  -a,--abort                abort test on late alarm\n"
+           "  -c,--count=<count>        number of times to suspend (default infinite)\n"
+           "  -t,--time=<seconds>       time to suspend for (default 5)\n"
+        );
+}
+
+int main(int argc, char **argv)
+{
+    int alarm_time = 5;
+    int count = -1;
+    bool abort_on_failure = false;
+
+    while (1) {
+        const static struct option long_options[] = {
+            {"abort", no_argument, 0, 'a'},
+            {"count", required_argument, 0, 'c'},
+            {"time", required_argument, 0, 't'},
+        };
+        int c = getopt_long(argc, argv, "ac:t:", long_options, NULL);
+        if (c < 0) {
+            break;
+        }
+
+        switch (c) {
+        case 'a':
+            abort_on_failure = true;
+            break;
+        case 'c':
+            count = strtoul(optarg, NULL, 0);
+            break;
+        case 't':
+            alarm_time = strtoul(optarg, NULL, 0);
+            break;
+        case '?':
+            usage();
+            exit(EXIT_FAILURE);
+        default:
+            abort();
+        }
+    }
+
+    klog_set_level(KLOG_INFO_LEVEL);
+
+    if (optind < argc) {
+        fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
+        usage();
+        exit(EXIT_FAILURE);
+    }
+
+    int fd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
+    if (fd < 0) {
+        perror("timerfd_create failed");
+        exit(EXIT_FAILURE);
+    }
+
+    struct itimerspec delay = itimerspec();
+    delay.it_value.tv_sec = alarm_time;
+    int i = 0;
+
+    int epoll_fd = epoll_create(1);
+    if (epoll_fd < 0) {
+        perror("epoll_create failed");
+        exit(EXIT_FAILURE);
+    }
+
+    struct epoll_event ev = epoll_event();
+    ev.events = EPOLLIN | EPOLLWAKEUP;
+    int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
+    if (ret < 0) {
+        perror("epoll_ctl failed");
+        exit(EXIT_FAILURE);
+    }
+
+    while (count != 0) {
+        struct timespec expected_time;
+        struct timespec actual_time;
+        uint64_t fired = 0;
+
+        ret = timerfd_settime(fd, 0, &delay, NULL);
+        if (ret < 0) {
+            perror("timerfd_settime failed");
+            exit(EXIT_FAILURE);
+        }
+
+        ret = clock_gettime(CLOCK_BOOTTIME, &expected_time);
+        if (ret < 0) {
+            perror("failed to get time");
+            exit(EXIT_FAILURE);
+        }
+        expected_time.tv_sec += alarm_time;
+
+        ret = 0;
+        while (ret != 1) {
+            struct epoll_event out_ev;
+            ret = epoll_wait(epoll_fd, &out_ev, 1, -1);
+            if (ret < 0 && errno != EINTR) {
+                perror("epoll_wait failed");
+                exit(EXIT_FAILURE);
+            }
+        }
+
+        ssize_t bytes = read(fd, &fired, sizeof(fired));
+        if (bytes < 0) {
+            perror("read from timer fd failed");
+            exit(EXIT_FAILURE);
+        } else if (bytes < (ssize_t)sizeof(fired)) {
+            fprintf(stderr, "unexpected read from timer fd: %zd\n", bytes);
+        }
+
+        if (fired != 1) {
+            fprintf(stderr, "unexpected timer fd fired count: %" PRIu64 "\n", fired);
+        }
+
+        ret = clock_gettime(CLOCK_BOOTTIME, &actual_time);
+        if (ret < 0) {
+            perror("failed to get time");
+            exit(EXIT_FAILURE);
+        }
+
+        long long diff = timediff_ns(&actual_time, &expected_time);
+        if (llabs(diff) > NSEC_PER_SEC) {
+            fprintf(stderr, "alarm arrived %lld.%03lld seconds %s\n",
+                    llabs(diff) / NSEC_PER_SEC,
+                    (llabs(diff) / NSEC_PER_MSEC) % MSEC_PER_SEC,
+                    diff > 0 ? "late" : "early");
+            KLOG_ERROR("suspend_stress", "alarm arrived %lld.%03lld seconds %s\n",
+                    llabs(diff) / NSEC_PER_SEC,
+                    (llabs(diff) / NSEC_PER_MSEC) % MSEC_PER_SEC,
+                    diff > 0 ? "late" : "early");
+            if (abort_on_failure) {
+                exit(EXIT_FAILURE);
+            }
+        }
+
+        time_t t = time(NULL);
+        i += fired;
+        printf("timer fired: %d at boottime %lld.%.3ld, %s", i,
+                   (long long)actual_time.tv_sec,
+                   actual_time.tv_nsec / NSEC_PER_MSEC,
+                   ctime(&t));
+
+        KLOG_INFO("suspend_stress", "timer fired: %d at boottime %lld.%.3ld, %s", i,
+                   (long long)actual_time.tv_sec,
+                   actual_time.tv_nsec / NSEC_PER_MSEC,
+                   ctime(&t));
+
+        if (count > 0)
+            count--;
+    }
+    return 0;
+}
diff --git a/tests/tcp_nuke_addr/Android.mk b/tests/tcp_nuke_addr/Android.mk
new file mode 100644
index 0000000..2eef608
--- /dev/null
+++ b/tests/tcp_nuke_addr/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := tcp_nuke_addr_test
+
+LOCAL_C_INCLUDES += frameworks/native/include external/libcxx/include
+LOCAL_CPPFLAGS += -std=c++11 -Wall -Werror
+LOCAL_SHARED_LIBRARIES := libc++
+LOCAL_SRC_FILES := tcp_nuke_addr_test.cpp
+LOCAL_MODULE_TAGS := eng tests
+
+include $(BUILD_NATIVE_TEST)
diff --git a/tests/tcp_nuke_addr/tcp_nuke_addr_test.cpp b/tests/tcp_nuke_addr/tcp_nuke_addr_test.cpp
new file mode 100644
index 0000000..587f768
--- /dev/null
+++ b/tests/tcp_nuke_addr/tcp_nuke_addr_test.cpp
@@ -0,0 +1,150 @@
+#include <arpa/inet.h>
+#include <linux/if.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <mutex>
+#include <thread>
+
+#include "utils/RWLock.h"
+
+// Defined only in ifc_utils.c, in the kernel, and in the NDK.
+#ifndef SIOCKILLADDR
+#define SIOCKILLADDR 0x8939
+#endif
+
+#ifndef TCP_LINGER2
+#define TCP_LINGER2 8
+#endif
+
+#define KILL_INTERVAL_MS 10
+#define CONNECT_THREADS 1
+
+#define PERROR_EXIT(msg) { do { perror((msg)); exit(1); } while (0); };
+
+
+// Ensures that sockets don't stay in TIME_WAIT state.
+void setSoLinger(int s) {
+    const struct linger l = {
+        0,  // off
+        0,  // 0 seconds
+    };
+    if (setsockopt(s, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1) {
+        PERROR_EXIT("SO_LINGER");
+    }
+    const int nolinger = -1;
+    if (setsockopt(s, SOL_TCP, TCP_LINGER2, &nolinger, sizeof(nolinger)) == -1) {
+        PERROR_EXIT("TCP_LINGER2");
+    }
+}
+
+
+// Binds to a random port on a random loopback address. We don't just use 127.0.0.1 because we don't
+// want this test to kill unrelated connections on loopback.
+int bindRandomAddr() {
+    sockaddr_in sin;
+    sin.sin_family = AF_INET;
+    sin.sin_port = 0;
+    sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    while (sin.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
+        arc4random_buf(
+             ((uint8_t *) &sin.sin_addr.s_addr) + 1,
+             sizeof(sin.sin_addr.s_addr) - 1);
+    }
+
+    int listensock;
+    if ((listensock = socket(AF_INET, SOCK_STREAM, 0)) == -1) PERROR_EXIT("listensock");
+    if (bind(listensock, (sockaddr *) &sin, sizeof(sin)) == -1) PERROR_EXIT("bind");
+    if (listen(listensock, 10) == -1) PERROR_EXIT("listen");
+
+    return listensock;
+}
+
+
+// Thread that calls SIOCKILLADDR in a loop.
+void killSockets(sockaddr_in listenaddr, int intervalMs, android::RWLock *lock) {
+    ifreq ifr;
+    memset(&ifr, 0, sizeof(ifr));
+    listenaddr.sin_port = 0;
+    strncpy(ifr.ifr_name, "lo", strlen("lo"));
+    memcpy(&ifr.ifr_addr, &listenaddr, sizeof(listenaddr));
+
+    int ioctlsock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (ioctlsock == -1) PERROR_EXIT("ioctlsock");
+    while(true) {
+        lock->writeLock();
+        if (ioctl(ioctlsock, SIOCKILLADDR, &ifr) != 0) {
+            PERROR_EXIT("SIOCKILLADDR failed, did you run 32-bit userspace on a 64-bit kernel?");
+        }
+        lock->unlock();
+        std::this_thread::sleep_for(std::chrono::milliseconds(intervalMs));
+    }
+}
+
+
+// Thread that calls connect() in a loop.
+void connectLoop(sockaddr_in listenaddr, int listensock,
+        android::RWLock *lock, std::atomic<unsigned int> *attempts) {
+    while(true) {
+        int s = socket(AF_INET, SOCK_STREAM, 0);
+        setSoLinger(s);
+
+        // Don't call SIOCKILLADDR while connect() is running, or we'll end up with lots of
+        // connections in state FIN_WAITx or TIME_WAIT, which will then slow down future
+        // due to SYN retransmits.
+        lock->readLock();
+        if (connect(s, (sockaddr *) &listenaddr, sizeof(listenaddr)) == -1) PERROR_EXIT("connect");
+        lock->unlock();
+
+        send(s, "foo", 3, 0);
+        int acceptedsock = accept(listensock, NULL, 0);
+        if (close(acceptedsock) == -1) PERROR_EXIT("close");
+        if (close(s) == -1) PERROR_EXIT("close");
+
+        attempts->fetch_add(1);
+    }
+}
+
+
+// Thread that prints progress every second.
+void progressThread(std::atomic<unsigned int> *attempts) {
+    uint32_t elapsed = 0;
+    uint32_t total, previous = 0;
+    while (true) {
+        std::this_thread::sleep_for(std::chrono::seconds(1));
+        elapsed++;
+        total = attempts->load();
+        printf("%ds: %u cps, total %u\n", elapsed, total-previous, total);
+        fflush(stdout);
+        previous = total;
+    }
+}
+
+
+int main() {
+    int listensock = bindRandomAddr();
+    struct sockaddr_in sin;
+    socklen_t len = sizeof(sin);
+    if (getsockname(listensock, (sockaddr *) &sin, &len) == -1) PERROR_EXIT("getsockname");
+
+    printf("Using address %s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+
+    android::RWLock lock;
+    std::atomic<unsigned int> attempts;
+    attempts.store(0);
+
+    std::thread t0(killSockets, sin, KILL_INTERVAL_MS, &lock);
+    std::thread *connectThreads[CONNECT_THREADS];
+    for (size_t i = 0; i < CONNECT_THREADS; i++) {
+        connectThreads[i] = new std::thread(connectLoop, sin, listensock, &lock, &attempts);
+    }
+    std::thread t1(progressThread, &attempts);
+    t1.join();
+
+    return 0;
+}
diff --git a/tests/timetest/Android.mk b/tests/timetest/Android.mk
new file mode 100644
index 0000000..b2a1aa5
--- /dev/null
+++ b/tests/timetest/Android.mk
@@ -0,0 +1,42 @@
+# Copyright 2006 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= timetest.c
+
+LOCAL_MODULE:= timetest
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
+LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
+
+LOCAL_STATIC_LIBRARIES := libc
+
+include $(BUILD_EXECUTABLE)
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
+
+test_c_flags := \
+    -fstack-protector-all \
+    -g \
+    -Wall -Wextra \
+    -Werror \
+    -fno-builtin \
+    -std=gnu++11
+
+test_src_files := \
+    rtc_test.cpp
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := time-unit-tests
+LOCAL_MODULE_TAGS := tests
+LOCAL_CFLAGS += $(test_c_flags)
+LOCAL_SRC_FILES := $(test_src_files)
+include $(BUILD_NATIVE_TEST)
+
diff --git a/tests/timetest/rtc_test.cpp b/tests/timetest/rtc_test.cpp
new file mode 100644
index 0000000..26ca13a
--- /dev/null
+++ b/tests/timetest/rtc_test.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/rtc.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+static int hwtime(int flag, int request, struct rtc_time *tm) {
+  static const char rtc[] = "/dev/rtc0";
+
+  int ret = TEMP_FAILURE_RETRY(access(rtc, flag & O_WRONLY) ? W_OK : R_OK);
+  if (ret < 0) {
+    ret = -errno;
+  }
+  if (ret == -EACCES) {
+    return ret;
+  }
+
+  if (flag & O_WRONLY) {
+    struct stat st;
+    ret = TEMP_FAILURE_RETRY(stat(rtc, &st));
+    if (ret < 0) {
+      ret = -errno;
+    } else if (!(st.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))) {
+      ret = -EACCES;
+    }
+  }
+  if (ret == -EACCES) {
+    return ret;
+  }
+
+  do {
+    ret = TEMP_FAILURE_RETRY(open(rtc, flag));
+    if (ret < 0) {
+      ret = -errno;
+    }
+  } while (ret == -EBUSY);
+  if (ret < 0) {
+    return ret;
+  }
+
+  int fd = ret;
+  do {
+    ret = TEMP_FAILURE_RETRY(ioctl(fd, request, tm));
+    if (ret < 0) {
+      ret = -errno;
+    }
+  } while (ret == -EBUSY);
+  close(fd);
+  return ret;
+}
+
+static int rd_hwtime(struct rtc_time *tm) {
+  return hwtime(O_RDONLY, RTC_RD_TIME, tm);
+}
+
+static int set_hwtime(struct rtc_time *tm) {
+  return hwtime(O_WRONLY, RTC_SET_TIME, tm);
+}
+
+static void rtc_rollover(int start, int end) {
+  struct rtc_time roll;
+  memset(&roll, 0, sizeof(roll));
+  ASSERT_LE(0, rd_hwtime(&roll));
+  int mday[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+  mday[1] = (roll.tm_year % 4) ? 28 : 29;
+  ASSERT_LE(0, roll.tm_sec);
+  ASSERT_GT(60, roll.tm_sec);
+  ASSERT_LE(0, roll.tm_min);
+  ASSERT_GT(60, roll.tm_min);
+  ASSERT_LE(0, roll.tm_hour);
+  ASSERT_GT(24, roll.tm_hour);
+  ASSERT_LE(0, roll.tm_mday);
+  ASSERT_GE(mday[roll.tm_mon], roll.tm_mday);
+  ASSERT_LE(0, roll.tm_mon);
+  ASSERT_GT(12, roll.tm_mon);
+  ASSERT_LE(0, roll.tm_year);
+  ASSERT_GT(138, roll.tm_year);
+
+  // Wait for granular clock
+  struct rtc_time save = roll;
+  static const useconds_t timeout_sleep = 10000;
+  static const int timeout_num = 2000000 / timeout_sleep;
+  int timeout;
+  for (timeout = timeout_num; timeout && (roll.tm_year == save.tm_year); --timeout) {
+    ASSERT_LE(0, rd_hwtime(&save));
+    usleep(timeout_sleep);
+  }
+
+  memset(&roll, 0, sizeof(roll));
+  roll.tm_sec = 59;
+  roll.tm_min = 59;
+  roll.tm_hour = 23;
+  roll.tm_mday = 31;
+  roll.tm_mon = 11;
+  roll.tm_year = 70;
+  roll.tm_wday = 0;
+  roll.tm_yday = 0;
+  roll.tm_isdst = 0;
+
+  bool eacces = true;
+  for (roll.tm_year = start; roll.tm_year < end; ++roll.tm_year) {
+    struct rtc_time tm = roll;
+    int __set_hwtime = set_hwtime(&tm);
+    // Allowed to be 100% denied for writing
+    if ((__set_hwtime == -EACCES) && (eacces == true)) {
+      continue;
+    }
+    eacces = false;
+    // below 2016, permitted to error out.
+    if ((__set_hwtime == -EINVAL) && (roll.tm_year < 116)) {
+      continue;
+    }
+    ASSERT_LE(0, __set_hwtime);
+    ASSERT_LE(0, rd_hwtime(&tm));
+    ASSERT_EQ(roll.tm_sec, tm.tm_sec);
+    ASSERT_EQ(roll.tm_min, tm.tm_min);
+    ASSERT_EQ(roll.tm_hour, tm.tm_hour);
+    ASSERT_EQ(roll.tm_mday, tm.tm_mday);
+    ASSERT_EQ(roll.tm_mon, tm.tm_mon);
+    ASSERT_EQ(roll.tm_year, tm.tm_year);
+    for (timeout = timeout_num; timeout && (roll.tm_year == tm.tm_year); --timeout) {
+      ASSERT_LE(0, rd_hwtime(&tm));
+      usleep(timeout_sleep);
+    }
+    ASSERT_EQ(roll.tm_year + 1, tm.tm_year);
+    EXPECT_LT(timeout_num * 5 / 100, timeout);
+    EXPECT_GT(timeout_num * 95 / 100, timeout);
+
+    // correct saved time to compensate for rollover check
+    if (++save.tm_sec >= 60) {
+      save.tm_sec = 0;
+      if (++save.tm_min >= 60) {
+        save.tm_min = 0;
+        if (++save.tm_hour >= 24) {
+          save.tm_hour = 0;
+          mday[1] = (save.tm_year % 4) ? 28 : 29;
+          if (++save.tm_mday >= mday[save.tm_mon]) {
+            save.tm_mday = 1;
+            if (++save.tm_mon >= 12) {
+              save.tm_mon = 0;
+              ++save.tm_year;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  if (!eacces) {
+    ASSERT_LE(0, set_hwtime(&save));
+  }
+  ASSERT_LE(0, rd_hwtime(&roll));
+
+  if (!eacces) {
+    ASSERT_EQ(save.tm_sec, roll.tm_sec);
+    ASSERT_EQ(save.tm_min, roll.tm_min);
+    ASSERT_EQ(save.tm_hour, roll.tm_hour);
+    ASSERT_EQ(save.tm_mday, roll.tm_mday);
+    ASSERT_EQ(save.tm_mon, roll.tm_mon);
+    ASSERT_EQ(save.tm_year, roll.tm_year);
+  }
+}
+
+TEST(time, rtc_rollover_1970_1990) {
+  rtc_rollover(70, 90);
+}
+
+TEST(time, rtc_rollover_1990_2010) {
+  rtc_rollover(90, 110);
+}
+
+TEST(time, rtc_rollover_2010_2030) {
+  rtc_rollover(110, 130);
+}
+
+TEST(time, rtc_rollover_2030_2037) {
+  rtc_rollover(130, 137);
+}
diff --git a/tests/timetest/timetest.c b/tests/timetest/timetest.c
new file mode 100644
index 0000000..baba36e
--- /dev/null
+++ b/tests/timetest/timetest.c
@@ -0,0 +1,113 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/limits.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+#include <string.h>
+
+
+
+long long nanotime(void)
+{
+    struct timespec t;
+    
+    if(clock_gettime(CLOCK_MONOTONIC, &t)) {
+        fprintf(stderr,"clock failure\n");
+        exit(1);
+    }
+
+    return (((long long) t.tv_sec) * 1000000000LL) +
+        ((long long) t.tv_nsec);
+}
+
+static struct timespec ts_sub(struct timespec a, struct timespec b)
+{
+    struct timespec r;
+    r.tv_sec = a.tv_sec - b.tv_sec;
+    r.tv_nsec = a.tv_nsec - b.tv_nsec;
+    if(r.tv_nsec < 0) {
+        r.tv_sec--;
+        r.tv_nsec += 1000 * 1000 * 1000;
+    }
+    if(r.tv_sec < 0 && r.tv_nsec > 0) {
+        r.tv_sec++;
+        r.tv_nsec -= 1000 * 1000 * 1000;
+    }
+    return r;
+}
+
+static struct timespec ts_min(struct timespec a, struct timespec b)
+{
+    if(a.tv_sec < b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_nsec < b.tv_nsec))
+        return a;
+    else
+        return b;
+}
+
+static struct timespec ts_max(struct timespec a, struct timespec b)
+{
+    if(a.tv_sec < b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_nsec < b.tv_nsec))
+        return b;
+    else
+        return a;
+}
+
+int main(int argc, char **argv)
+{
+    long long tnow, tlast;
+    struct timespec t1, dtmin, dtminp, dtmax;
+    int print_interval = 50000;
+    int print_countdown = 1;
+    int clock_id = CLOCK_MONOTONIC;
+    dtmin.tv_sec = INT_MAX;
+    dtmin.tv_nsec = 0;
+    dtminp.tv_sec = INT_MAX;
+    dtminp.tv_nsec = 0;
+    dtmax.tv_sec = 0;
+    dtmax.tv_nsec = 0;
+    tlast = 0;
+
+    if(argc == 2) {
+        clock_id = atoi(argv[1]);
+        printf("using clock %d\n", clock_id);
+    }
+    clock_gettime(clock_id, &t1);
+    
+    for(;;) {
+        struct timespec t, dt;
+        clock_gettime(clock_id, &t);
+        dt = ts_sub(t, t1);
+        t1 = t;
+        dtmin = ts_min(dtmin, dt);
+        if(dt.tv_sec > 0 || dt.tv_nsec > 0)
+            dtminp = ts_min(dtminp, dt);
+        if(print_countdown != print_interval)
+            dtmax = ts_max(dtmax, dt);
+        if(--print_countdown == 0) {
+            fprintf(stderr,"%09ld.%09ld, dt %ld.%09ld, min %ld.%09ld, minp %ld.%09ld, max %ld.%09ld\n",
+                    t.tv_sec, t.tv_nsec, dt.tv_sec, dt.tv_nsec,
+                    dtmin.tv_sec, dtmin.tv_nsec, dtminp.tv_sec, dtminp.tv_nsec,
+                    dtmax.tv_sec, dtmax.tv_nsec);
+            print_countdown = print_interval;
+        }
+    }
+    for(;;) {
+        tnow = nanotime();
+        if(tnow < tlast) {
+#if 0
+            fprintf(stderr,"time went backwards: %lld -> %lld\n",
+                    tlast, tnow);
+            exit(1);
+#endif
+            fprintf(stderr,"%lld ROLLBACK\n", tnow);
+        } else {
+            fprintf(stderr,"%lld\n", tnow);
+        }
+        tlast = tnow;
+    }
+
+    return 0;
+}
diff --git a/tests/uevents/Android.mk b/tests/uevents/Android.mk
new file mode 100644
index 0000000..fb8a851
--- /dev/null
+++ b/tests/uevents/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := uevents.c
+
+LOCAL_SHARED_LIBRARIES += libcutils
+LOCAL_MODULE:= uevents
+
+LOCAL_CFLAGS := -Wno-unused-parameter
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/uevents/uevents.c b/tests/uevents/uevents.c
new file mode 100644
index 0000000..1ca4cfe
--- /dev/null
+++ b/tests/uevents/uevents.c
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#include <cutils/uevent.h>
+#include <stdio.h>
+
+#define UEVENT_MSG_LEN  1024
+
+int main(int argc, char *argv[])
+{
+    int device_fd;
+    char msg[UEVENT_MSG_LEN+2];
+    int n;
+    int i;
+
+    device_fd = uevent_open_socket(64*1024, true);
+    if(device_fd < 0)
+        return -1;
+
+    while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
+        msg[n] = '\0';
+        msg[n+1] = '\0';
+
+        for (i = 0; i < n; i++)
+            if (msg[i] == '\0')
+                msg[i] = ' ';
+
+        printf("%s\n", msg);
+    }
+
+    return 0;
+}
diff --git a/tests/wifi/Android.mk b/tests/wifi/Android.mk
new file mode 100644
index 0000000..4343259
--- /dev/null
+++ b/tests/wifi/Android.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2010 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.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/tests/wifi/stress/Android.mk b/tests/wifi/stress/Android.mk
new file mode 100644
index 0000000..2361483
--- /dev/null
+++ b/tests/wifi/stress/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2010 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.
+# Copyright The Android Open Source Project
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := wifiLoadScanAssoc
+LOCAL_SRC_FILES := wifiLoadScanAssoc.c
+LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libhardware_legacy
+LOCAL_STATIC_LIBRARIES += libtestUtil
+LOCAL_C_INCLUDES += system/extras/tests/include \
+    hardware/libhardware_legacy/include
+
+include $(BUILD_NATIVE_TEST)
diff --git a/tests/wifi/stress/wifiLoadScanAssoc.c b/tests/wifi/stress/wifiLoadScanAssoc.c
new file mode 100644
index 0000000..5dc2692
--- /dev/null
+++ b/tests/wifi/stress/wifiLoadScanAssoc.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2010 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.
+ *
+ */
+
+/*
+ * WiFi load, scan, associate, unload stress test
+ *
+ * Repeatedly executes the following sequence:
+ *
+ *   1. Load WiFi driver
+ *   2. Start supplicant
+ *   3. Random delay
+ *   4. Obtain supplicant status (optional)
+ *   5. Stop supplicant
+ *   6. Unload WiFi driver
+ *
+ * The "Obtain supplicant status" step is optional and is pseudo
+ * randomly performed 50% of the time.  The default range of
+ * delay after start supplicant is intentionally selected such
+ * that the obtain supplicant status and stop supplicant steps
+ * may be performed while the WiFi driver is still performing a scan
+ * or associate.  The default values are given by DEFAULT_DELAY_MIN
+ * and DEFAULT_DELAY_MAX.  Other values can be specified through the
+ * use of the -d and -D command-line options.
+ *
+ * Each sequence is refered to as a pass and by default an unlimited
+ * number of passes are performed.  An override of the range of passes
+ * to be executed is available through the use of the -s (start) and
+ * -e (end) command-line options.  Can also specify a single specific
+ * pass via the -p option.  There is also a default time in which the
+ * test executes, which is given by DEFAULT_DURATION and can be overriden
+ * through the use of the -t command-line option.
+ */
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <errno.h>
+#include <libgen.h>
+#include <math.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <hardware_legacy/wifi.h>
+
+#define LOG_TAG "wifiLoadScanAssocTest"
+#include <utils/Log.h>
+#include <testUtil.h>
+
+#define DEFAULT_START_PASS     0
+#define DEFAULT_END_PASS     999
+#define DEFAULT_DURATION       FLT_MAX // A fairly long time, so that
+                                       // range of passes will have
+                                       // precedence
+#define DEFAULT_DELAY_MIN      0.0     // Min delay after start supplicant
+#define DEFAULT_DELAY_MAX     20.0     // Max delay after start supplicant
+#define DELAY_EXP            150.0     // Exponent which determines the
+                                       // amount by which values closer
+                                       // to DELAY_MIN are favored.
+
+#define CMD_STATUS           "wpa_cli status 2>&1"
+#define CMD_STOP_FRAMEWORK   "stop 2>&1"
+#define CMD_START_FRAMEWORK  "start 2>&1"
+
+#define MAXSTR      100
+#define MAXCMD      500
+
+typedef unsigned int bool_t;
+#define true (0 == 0)
+#define false (!true)
+
+// File scope variables
+cpu_set_t availCPU;
+unsigned int numAvailCPU;
+float delayMin = DEFAULT_DELAY_MIN;
+float delayMax = DEFAULT_DELAY_MAX;
+bool_t driverLoadedAtStart;
+
+// Command-line mutual exclusion detection flags.
+// Corresponding flag set true once an option is used.
+bool_t eFlag, sFlag, pFlag;
+
+// File scope prototypes
+static void init(void);
+static void randDelay(void);
+static void randBind(const cpu_set_t *availSet, int *chosenCPU);
+
+/*
+ * Main
+ *
+ * Performs the following high-level sequence of operations:
+ *
+ *   1. Command-line parsing
+ *
+ *   2. Initialization
+ *
+ *   3. Execute passes that repeatedly perform the WiFi load, scan,
+ *      associate, unload sequence.
+ *
+ *   4. Restore state of WiFi driver to state it was at the
+ *      start of the test.
+ *
+ *   5. Restart framework
+ */
+int
+main(int argc, char *argv[])
+{
+    FILE *fp;
+    int rv, opt;
+    int cpu;
+    char *chptr;
+    unsigned int pass;
+    char cmd[MAXCMD];
+    float duration = DEFAULT_DURATION;
+    unsigned int startPass = DEFAULT_START_PASS, endPass = DEFAULT_END_PASS;
+    struct timeval startTime, currentTime, delta;
+
+    testSetLogCatTag(LOG_TAG);
+
+    // Parse command line arguments
+    while ((opt = getopt(argc, argv, "d:D:s:e:p:t:?")) != -1) {
+        switch (opt) {
+        case 'd': // Minimum Delay
+            delayMin = strtod(optarg, &chptr);
+            if ((*chptr != '\0') || (delayMin < 0.0)) {
+                testPrintE("Invalid command-line specified minimum delay "
+                    "of: %s", optarg);
+                exit(1);
+            }
+            break;
+
+        case 'D': // Maximum Delay
+            delayMax = strtod(optarg, &chptr);
+            if ((*chptr != '\0') || (delayMax < 0.0)) {
+                testPrintE("Invalid command-line specified maximum delay "
+                    "of: %s", optarg);
+                exit(2);
+            }
+            break;
+
+        case 't': // Duration
+            duration = strtod(optarg, &chptr);
+            if ((*chptr != '\0') || (duration < 0.0)) {
+                testPrintE("Invalid command-line specified duration of: %s",
+                    optarg);
+                exit(3);
+            }
+            break;
+
+        case 's': // Starting Pass
+            if (sFlag || pFlag) {
+                testPrintE("Invalid combination of command-line options,");
+                if (sFlag) {
+                    testPrintE("  -s flag specified multiple times.");
+                } else {
+                    testPrintE("  -s and -p flags are mutually exclusive.");
+                }
+                exit(10);
+            }
+            sFlag = true;
+            startPass = strtoul(optarg, &chptr, 10);
+            if (*chptr != '\0') {
+                testPrintE("Invalid command-line specified starting pass "
+                    "of: %s", optarg);
+                exit(4);
+            }
+            break;
+
+        case 'e': // Ending Pass
+            if (eFlag || pFlag) {
+                testPrintE("Invalid combination of command-line options,");
+                if (sFlag) {
+                    testPrintE("  -e flag specified multiple times.");
+                } else {
+                    testPrintE("  -e and -p flags are mutually exclusive.");
+                }
+                exit(11);
+            }
+            eFlag = true;
+            endPass = strtoul(optarg, &chptr, 10);
+            if (*chptr != '\0') {
+                testPrintE("Invalid command-line specified ending pass "
+                    "of: %s", optarg);
+                exit(5);
+            }
+            break;
+
+        case 'p': // Single Specific Pass
+            if (pFlag || sFlag || eFlag) {
+                testPrintE("Invalid combination of command-line options,");
+                if (pFlag) {
+                    testPrintE("  -p flag specified multiple times.");
+                } else {
+                    testPrintE("  -p and -%c flags are mutually exclusive.",
+                        (sFlag) ? 's' : 'e');
+                }
+                exit(12);
+            }
+            pFlag = true;
+            endPass = startPass = strtoul(optarg, &chptr, 10);
+            if (*chptr != '\0') {
+                testPrintE("Invalid command-line specified pass "
+                    "of: %s", optarg);
+                exit(13);
+            }
+            break;
+
+        case '?':
+        default:
+            testPrintE("  %s [options]", basename(argv[0]));
+            testPrintE("    options:");
+            testPrintE("      -s Starting pass");
+            testPrintE("      -e Ending pass");
+            testPrintE("      -p Specific single pass");
+            testPrintE("      -t Duration");
+            testPrintE("      -d Delay min");
+            testPrintE("      -D Delay max");
+            exit(((optopt == 0) || (optopt == '?')) ? 0 : 6);
+        }
+    }
+    if (delayMax < delayMin) {
+        testPrintE("Unexpected maximum delay less than minimum delay");
+        testPrintE("  delayMin: %f delayMax: %f", delayMin, delayMax);
+        exit(7);
+    }
+    if (endPass < startPass) {
+        testPrintE("Unexpected ending pass before starting pass");
+        testPrintE("  startPass: %u endPass: %u", startPass, endPass);
+        exit(8);
+    }
+    if (argc != optind) {
+        testPrintE("Unexpected command-line postional argument");
+        testPrintE("  %s [-s start_pass] [-e end_pass] [-d duration]",
+            basename(argv[0]));
+        exit(9);
+    }
+    testPrintI("duration: %g", duration);
+    testPrintI("startPass: %u", startPass);
+    testPrintI("endPass: %u", endPass);
+    testPrintI("delayMin: %f", delayMin);
+    testPrintI("delayMax: %f", delayMax);
+
+    init();
+
+    // For each pass
+    gettimeofday(&startTime, NULL);
+    for (pass = startPass; pass <= endPass; pass++) {
+        // Stop if duration of work has already been performed
+        gettimeofday(&currentTime, NULL);
+        delta = tvDelta(&startTime, &currentTime);
+        if (tv2double(&delta) > duration) { break; }
+
+        testPrintI("==== Starting pass: %u", pass);
+
+        // Use a pass dependent sequence of random numbers
+        srand48(pass);
+
+        // Load WiFi Driver
+        randBind(&availCPU, &cpu);
+        if ((rv = wifi_load_driver()) != 0) {
+            testPrintE("CPU: %i wifi_load_driver() failed, rv: %i\n",
+                cpu, rv);
+            exit(20);
+        }
+        testPrintI("CPU: %i wifi_load_driver succeeded", cpu);
+
+        // Start Supplicant
+        randBind(&availCPU, &cpu);
+        if ((rv = wifi_start_supplicant(false)) != 0) {
+            testPrintE("CPU: %i wifi_start_supplicant() failed, rv: %i\n",
+                cpu, rv);
+            exit(21);
+        }
+        testPrintI("CPU: %i wifi_start_supplicant succeeded", cpu);
+
+        // Sleep a random amount of time
+        randDelay();
+
+        /*
+         * Obtain WiFi Status
+         * Half the time skip this step, which helps increase the
+         * level of randomization.
+         */
+        if (testRandBool()) {
+            rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STATUS);
+            if (rv >= (signed) sizeof(cmd) - 1) {
+                testPrintE("Command too long for: %s\n", CMD_STATUS);
+                exit(22);
+            }
+            testExecCmd(cmd);
+        }
+
+        // Stop Supplicant
+        randBind(&availCPU, &cpu);
+        if ((rv = wifi_stop_supplicant(false)) != 0) {
+            testPrintE("CPU: %i wifi_stop_supplicant() failed, rv: %i\n",
+                cpu, rv);
+            exit(23);
+        }
+        testPrintI("CPU: %i wifi_stop_supplicant succeeded", cpu);
+
+        // Unload WiFi Module
+        randBind(&availCPU, &cpu);
+        if ((rv = wifi_unload_driver()) != 0) {
+            testPrintE("CPU: %i wifi_unload_driver() failed, rv: %i\n",
+                cpu, rv);
+            exit(24);
+        }
+        testPrintI("CPU: %i wifi_unload_driver succeeded", cpu);
+
+        testPrintI("==== Completed pass: %u", pass);
+    }
+
+    // If needed restore WiFi driver to state it was in at the
+    // start of the test.  It is assumed that it the driver
+    // was loaded, then the wpa_supplicant was also running.
+    if (driverLoadedAtStart) {
+        // Load driver
+        if ((rv = wifi_load_driver()) != 0) {
+            testPrintE("main load driver failed, rv: %i", rv);
+            exit(25);
+        }
+
+        // Start supplicant
+        if ((rv = wifi_start_supplicant(false)) != 0) {
+            testPrintE("main start supplicant failed, rv: %i", rv);
+            exit(26);
+        }
+
+        // Obtain WiFi Status
+        rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STATUS);
+        if (rv >= (signed) sizeof(cmd) - 1) {
+            testPrintE("Command too long for: %s\n", CMD_STATUS);
+            exit(22);
+        }
+        testExecCmd(cmd);
+    }
+
+    // Start framework
+    rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
+    if (rv >= (signed) sizeof(cmd) - 1) {
+        testPrintE("Command too long for: %s\n", CMD_START_FRAMEWORK);
+        exit(27);
+    }
+    testExecCmd(cmd);
+
+    testPrintI("Successfully completed %u passes", pass - startPass);
+
+    return 0;
+}
+
+/*
+ * Initialize
+ *
+ * Perform testcase initialization, which includes:
+ *
+ *   1. Determine which CPUs are available for use
+ *
+ *   2. Determine total number of available CPUs
+ *
+ *   3. Stop framework
+ *
+ *   4. Determine whether WiFi driver is loaded and if so
+ *      stop wpa_supplicant and unload WiFi driver.
+ */
+void
+init(void)
+{
+    int rv;
+    unsigned int n1;
+    char cmd[MAXCMD];
+
+    // Use whichever CPUs are available at start of test
+    rv = sched_getaffinity(0, sizeof(availCPU), &availCPU);
+    if (rv != 0) {
+        testPrintE("init sched_getaffinity failed, rv: %i errno: %i",
+            rv, errno);
+        exit(40);
+    }
+
+    // How many CPUs are available
+    numAvailCPU = 0;
+    for (n1 = 0; n1 < CPU_SETSIZE; n1++) {
+        if (CPU_ISSET(n1, &availCPU)) { numAvailCPU++; }
+    }
+    testPrintI("numAvailCPU: %u", numAvailCPU);
+
+    // Stop framework
+    rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK);
+    if (rv >= (signed) sizeof(cmd) - 1) {
+        testPrintE("Command too long for: %s\n", CMD_STOP_FRAMEWORK);
+        exit(41);
+    }
+    testExecCmd(cmd);
+
+    // Is WiFi driver loaded?
+    // If so stop the wpa_supplicant and unload the driver.
+    driverLoadedAtStart = is_wifi_driver_loaded();
+    testPrintI("driverLoadedAtStart: %u", driverLoadedAtStart);
+    if (driverLoadedAtStart) {
+        // Stop wpa_supplicant
+        // Might already be stopped, in which case request should
+        // return immediately with success.
+        if ((rv = wifi_stop_supplicant(false)) != 0) {
+            testPrintE("init stop supplicant failed, rv: %i", rv);
+            exit(42);
+        }
+        testPrintI("Stopped wpa_supplicant");
+
+        if ((rv = wifi_unload_driver()) != 0) {
+            testPrintE("init unload driver failed, rv: %i", rv);
+            exit(43);
+        }
+        testPrintI("WiFi driver unloaded");
+    }
+
+}
+
+/*
+ * Random Delay
+ *
+ * Delays for a random amount of time within the range given
+ * by the file scope variables delayMin and delayMax.  The
+ * selected amount of delay can come from any part of the
+ * range, with a bias towards values closer to delayMin.
+ * The amount of bias is determined by the setting of DELAY_EXP.
+ * The setting of DELAY_EXP should always be > 1.0, with higher
+ * values causing a more significant bias toward the value
+ * of delayMin.
+ */
+void randDelay(void)
+{
+    const unsigned long nanosecspersec = 1000000000;
+    float            fract, biasedFract, amt;
+    struct timeval   startTime, endTime;
+
+    // Obtain start time
+    gettimeofday(&startTime, NULL);
+
+    // Determine random amount to sleep.
+    // Values closer to delayMin are prefered by an amount
+    // determined by the value of DELAY_EXP.
+    fract = testRandFract();
+    biasedFract = pow(DELAY_EXP, fract) / pow(DELAY_EXP, 1.0);
+    amt = delayMin + ((delayMax - delayMin) * biasedFract);
+
+    // Delay
+    testDelay(amt);
+
+    // Obtain end time and display delta
+    gettimeofday(&endTime, NULL);
+    testPrintI("delay: %.2f",
+        (float) (tv2double(&endTime) - tv2double(&startTime)));
+}
+
+static void
+randBind(const cpu_set_t *availSet, int *chosenCPU)
+{
+    int rv;
+    cpu_set_t cpuset;
+    int chosenAvail, avail, cpu, currentCPU;
+
+    // Randomly bind to a CPU
+    // Lower 16 bits from random number generator thrown away,
+    // because the low-order bits tend to have the same sequence for
+    // different seed values.
+    chosenAvail = testRandMod(numAvailCPU);
+    CPU_ZERO(&cpuset);
+    avail = 0;
+    for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
+        if (CPU_ISSET(cpu, availSet)) {
+            if (chosenAvail == avail) {
+                CPU_SET(cpu, &cpuset);
+                break;
+            }
+            avail++;
+        }
+    }
+    assert(cpu < CPU_SETSIZE);
+    sched_setaffinity(0, sizeof(cpuset), &cpuset);
+
+    // Confirm executing on requested CPU
+    if ((currentCPU = sched_getcpu()) < 0) {
+        testPrintE("randBind sched_getcpu() failed, rv: %i errno: %i",
+                   currentCPU, errno);
+        exit(80);
+
+    }
+    if (currentCPU != cpu) {
+        testPrintE("randBind executing on unexpected CPU %i, expected %i",
+            currentCPU, cpu);
+        exit(81);
+    }
+
+    // Let the caller know which CPU was chosen
+    *chosenCPU = cpu;
+}
diff --git a/tests/workloads/atrace-uncompress.py b/tests/workloads/atrace-uncompress.py
new file mode 100644
index 0000000..5efb698
--- /dev/null
+++ b/tests/workloads/atrace-uncompress.py
@@ -0,0 +1,35 @@
+#
+# Uncompress a file generated via atrace -z
+#
+# Usage: python atrace-uncompress.py infile > outfile
+#
+import sys, zlib
+
+def main():
+
+	if len(sys.argv) != 2:
+		print >> sys.stderr, ('Usage: %s inputfile' % sys.argv[0])
+		sys.exit(1)
+
+	infile = open(sys.argv[1], "rb")
+	out = infile.read()
+	parts = out.split('\nTRACE:', 1)
+
+	data = ''.join(parts[1])
+
+	# Remove CR characters
+	if data.startswith('\r\n'):
+		data = data.replace('\r\n', '\n')
+
+	# Skip the initial newline.
+	data = data[1:]
+
+	if not data:
+		print >> sys.stderr, ('No trace data found')
+		sys.exit(1)
+
+	out = zlib.decompress(data)
+	print(out)
+
+if __name__ == '__main__':
+	main()
diff --git a/tests/workloads/capture.sh b/tests/workloads/capture.sh
new file mode 100755
index 0000000..3b2f446
--- /dev/null
+++ b/tests/workloads/capture.sh
Binary files differ
diff --git a/tests/workloads/defs.sh b/tests/workloads/defs.sh
new file mode 100755
index 0000000..a2b7138
--- /dev/null
+++ b/tests/workloads/defs.sh
Binary files differ
diff --git a/tests/workloads/feedly-chrome.sh b/tests/workloads/feedly-chrome.sh
new file mode 100755
index 0000000..4c7002f
--- /dev/null
+++ b/tests/workloads/feedly-chrome.sh
@@ -0,0 +1,111 @@
+# Script to automate the following sequence:
+# - Open Feedly
+# - Open an article
+# - Scroll to bottome
+# - Open the same article in Chrome
+# - Scroll the article
+# - Back to Feely (should still be in memory)
+# - Home screen
+# ---- repeat ----
+#
+# Currently works on volantis only (verticle orientation)
+#
+
+CMDDIR=$(dirname $0 2>/dev/null)
+CMDDIR=${CMDDIR:=.}
+. $CMDDIR/defs.sh
+
+case "$DEVICE" in
+(volantis)
+	echo volantis...
+	feedlyArticle="500 700"
+	feedlyOptions="1480 100"
+	feedlyBrowserSelect="1350 650"
+	feedlyArticleSwipeUp="700 700 700 50 50"
+	feedlyArticleSwipeDown="700 200 700 700 50"
+	chromeSwipe="700 700 700 50 50"
+	;;
+(shamu|*)
+	echo shamu...
+	feedlyArticle="676 500"
+	feedlyOptions="1327 207"
+	feedlyBrowserSelect="1278 1191"
+	feedlyArticleSwipeUp="700 1847 700 400 50"
+	feedlyArticleSwipeDown="700 400 700 1847 50"
+	chromeSwipe="700 1847 700 400 50"
+	;;
+(hammerhead|*)
+	echo "Error: No feedly screen geometry information available for $DEVICE"
+	exit 1;;
+esac
+
+feedlySwitchToTime=600
+
+# start feedly, if not installed, error out
+t=$(forceStartActivity feedly)
+checkIsRunning feedly "initial start of feedly"
+echo Feedly start time = ${t}ms
+
+# start chrome, if not installed, error out
+t=$(forceStartActivity chrome)
+checkIsRunning chrome "initial start of chrome"
+echo Chrome start time = ${t}ms
+sleep 1
+
+feedlyStartTimes=0
+
+cur=1
+while [ $cur -le $iterations ]
+do
+	echo =======================================
+	echo Iteration $cur of $iterations
+	echo =======================================
+	startInstramentation
+	t=$(startActivity feedly)
+	if [ $(checkStartTime "$t" $feedlySwitchToTime) != true ]; then
+		handleError Feedly took too long to start: $t v $feedlySwitchToTime: $?
+		# for now, not fatal
+		# exit 1
+	fi
+	sleep 2
+	((feedlyStartTimes=feedlyStartTimes+t))
+	echo feedly started in ${t}ms
+	checkIsRunning chrome "switch back to feedly"
+	checkIsRunning googlequicksearchbox "switch back to feedly"
+
+	# click on first article
+	doTap $feedlyArticle
+	sleep 2
+
+	# scroll through article
+	doSwipe $feedlyArticleSwipeUp
+	sleep 5
+	checkIsRunning chrome "feedly swipe"
+	checkIsRunning googlequicksearchbox "feedly swipe"
+
+	# scroll back to top
+	doSwipe $feedlyArticleSwipeDown
+	sleep 2
+
+	# switch to chrome
+	# 1. click on menu bar
+	doTap $feedlyOptions
+	sleep 1
+	# 2. click on browser
+	doTap $feedlyBrowserSelect
+	sleep 10
+
+	checkIsRunning feedly "switch to chrome"
+	checkIsRunning googlequicksearchbox "switch to chrome"
+
+	# Now we're back in chrome, swipe to bottom of article
+	doSwipe $chromeSwipe
+	sleep 2
+	checkIsRunning feedly "swiped chrome"
+	stopInstramentation
+	((cur=cur+1))
+done
+((feedlyAve=feedlyStartTimes/iterations))
+echo Avg start times: feedly: ${feedlyAve}ms
+
+doKeyevent HOME
diff --git a/tests/workloads/recentfling.sh b/tests/workloads/recentfling.sh
new file mode 100755
index 0000000..092c8d9
--- /dev/null
+++ b/tests/workloads/recentfling.sh
@@ -0,0 +1,150 @@
+#
+# Script to start a set of apps, switch to recents and fling it back and forth.
+# For each iteration, Total frames and janky frames are reported.
+#
+# Options are described below.
+#
+# Works for volantis, shamu, and hammerhead. Can be pushed and executed on
+# the device.
+#
+iterations=10
+startapps=1
+capturesystrace=0
+
+function processLocalOption {
+	ret=0
+	case "$1" in
+	(-N) startapps=0;;
+	(-A) unset appList;;
+	(-L) appList=$2; shift; ret=1;;
+	(-T) capturesystrace=1;;
+	(*)
+		echo "$0: unrecognized option: $1"
+		echo; echo "Usage: $0 [options]"
+		echo "-A : use all known applications"
+		echo "-L applist : list of applications"
+		echo "   default: $appList"
+		echo "-N : no app startups, just fling"
+		echo "-g : generate activity strings"
+		echo "-i iterations"
+		echo "-T : capture systrace on each iteration"
+		exit 1;;
+	esac
+	return $ret
+}
+
+CMDDIR=$(dirname $0 2>/dev/null)
+CMDDIR=${CMDDIR:=.}
+. $CMDDIR/defs.sh
+
+case $DEVICE in
+(shamu|hammerhead)
+	flingtime=300
+	downCount=2
+	upCount=6
+	UP="70 400 70 100 $flingtime"
+	DOWN="70 100 70 400 $flingtime";;
+(bullhead)
+	flingtime=200
+	downCount=5
+	upCount=5
+	UP="500 1200 500 550 $flingtime"
+	DOWN="500 550 500 1200 $flingtime";;
+(volantis)
+	flingtime=400
+	downCount=5
+	upCount=6
+	UP="70 400 70 70 $flingtime"
+	DOWN="70 70 70 400 $flingtime";;
+(*)
+	echo "Error: No display information available for $DEVICE"
+	exit 1;;
+esac
+
+doKeyevent HOME
+if [ $startapps -gt 0 ]; then
+
+	# start a bunch of apps
+	for app in $appList
+	do
+		echo Starting $app ...
+		t=$(startActivity $app)
+	done
+fi
+
+function swipe {
+	count=0
+	while [ $count -lt $2 ]
+	do
+		doSwipe $1
+		((count=count+1))
+	done
+}
+
+cur=1
+frameSum=0
+jankSum=0
+latency90Sum=0
+latency95Sum=0
+latency99Sum=0
+
+echo Fling recents...
+doKeyevent HOME
+sleep 0.5
+resetJankyFrames
+
+while [ $cur -le $iterations ]
+do
+	if [ $capturesystrace -gt 0 ]; then
+		${ADB}atrace --async_start -z -c -b 16000 freq gfx view idle sched
+	fi
+	doKeyevent APP_SWITCH
+	sleep 0.5
+	swipe "$DOWN" $downCount
+	sleep 1
+	swipe "$UP" $upCount
+	sleep 1
+	swipe "$DOWN" $downCount
+	sleep 1
+	swipe "$UP" $upCount
+	sleep 1
+	if [ $capturesystrace -gt 0 ]; then
+		${ADB}atrace --async_dump -z -c -b 16000 freq gfx view idle sched > trace.${cur}.out
+	fi
+	doKeyevent HOME
+	sleep 0.5
+
+	set -- $(getJankyFrames)
+	totalDiff=$1
+	jankyDiff=$2
+	latency90=$3
+	latency95=$4
+	latency99=$5
+	if [ ${totalDiff:=0} -eq 0 ]; then
+		echo Error: could not read frame info with \"dumpsys gfxinfo\"
+		exit 1
+	fi
+
+	((frameSum=frameSum+totalDiff))
+	((jankSum=jankSum+jankyDiff))
+	((latency90Sum=latency90Sum+latency90))
+	((latency95Sum=latency95Sum+latency95))
+	((latency99Sum=latency99Sum+latency99))
+	if [ "$totalDiff" -eq 0 ]; then
+		echo Error: no frames detected. Is the display off?
+		exit 1
+	fi
+	((jankPct=jankyDiff*100/totalDiff))
+	resetJankyFrames
+
+	echo Frames: $totalDiff latency: $latency90/$latency95/$latency99 Janks: $jankyDiff\(${jankPct}%\)
+	((cur=cur+1))
+done
+doKeyevent HOME
+((aveJankPct=jankSum*100/frameSum))
+((aveJanks=jankSum/iterations))
+((aveFrames=frameSum/iterations))
+((aveLatency90=latency90Sum/iterations))
+((aveLatency95=latency95Sum/iterations))
+((aveLatency99=latency99Sum/iterations))
+echo AVE: Frames: $aveFrames latency: $aveLatency90/$aveLatency95/$aveLatency99 Janks: $aveJanks\(${aveJankPct}%\)
diff --git a/tests/workloads/systemapps.sh b/tests/workloads/systemapps.sh
new file mode 100755
index 0000000..a263e7d
--- /dev/null
+++ b/tests/workloads/systemapps.sh
@@ -0,0 +1,264 @@
+# Script to start a set of apps in order and then in each iteration
+# switch the focus to each one. For each iteration, the time to start
+# the app is reported as measured using atrace events and via am ThisTime.
+# The output also reports if applications are restarted (eg, killed by
+# LMK since previous iteration) or if there were any direct reclaim
+# events.
+#
+# Variation: the "-T" option skips all of the atrace instramentation and
+# attempts to start the apps as quickly as possible.
+#
+# Example 1: start all default apps. 2 iterations
+#
+# ./systemapps.sh -i 2
+#
+# Example 2: just start chrome, feedly, and the home screen in a loop
+#
+# ./systemapps.sh -L "chrome feedly home" -i 5
+#
+# Example 3: just start the default apps as quickly as possible
+#
+# ./systemapps.sh -T
+#
+# Other options are described below.
+#
+iterations=1
+tracecategories="gfx view am input memreclaim"
+totaltimetest=0
+forcecoldstart=0
+waitTime=3.0
+
+appList="gmail hangouts chrome youtube play home"
+
+function processLocalOption {
+	ret=0
+	case "$1" in
+	(-A) unset appList;;
+	(-F) forcecoldstart=1;;
+	(-L) appList=$2; shift; ret=1;;
+	(-T) totaltimetest=1;;
+	(-W) waitTime=$2; shift; ret=1;;
+	(*)
+		echo "$0: unrecognized option: $1"
+		echo; echo "Usage: $0 [options]"
+		echo "-A : use all known applications"
+		echo "-F : force cold-start for all apps"
+		echo "-L applist : list of applications"
+		echo "   default: $appList"
+		echo "-T : total time to start all apps"
+		echo "-W : time to wait between apps"
+		echo "-g : generate activity strings"
+		echo "-i iterations"
+		echo "-n : keep trace files"
+		echo "-o output file"
+		echo "-s : stop on error"
+		echo "-t trace categories"
+		exit 1;;
+	esac
+	return $ret
+}
+
+CMDDIR=$(dirname $0 2>/dev/null)
+CMDDIR=${CMDDIR:=.}
+. $CMDDIR/defs.sh
+
+tmpTraceOutBase=./tmptrace
+
+if [ $user !=  "root" -a $totaltimetest -eq 0 ]; then
+	handleError Must be root on device
+	exit 1
+fi
+doKeyevent HOME
+
+function computeStats {
+	label=$1
+	t=$2
+	restart=$3
+	reclaim=$4
+	frames=$5
+	janks=$6
+	l90=$7
+	l95=$8
+	l99=$9
+	curMax=$(eval "echo \$${label}max")
+	curMax=${curMax:=0}
+	curMin=$(eval "echo \$${label}min")
+	curMin=${curMin:=100000}
+	curSum=$(eval "echo \$${label}sum")
+	curSum=${curSum:=0}
+	curRestart=$(eval "echo \$${label}restart")
+	curRestart=${curRestart:=0}
+	curReclaim=$(eval "echo \$${label}reclaim")
+	curReclaim=${curReclaim:=0}
+	curFrames=$(eval "echo \$${label}frames")
+	curFrames=${curFrames:=0}
+	curJanks=$(eval "echo \$${label}janks")
+	curJanks=${curJanks:=0}
+	cur90=$(eval "echo \$${label}90")
+	cur90=${cur90:=0}
+	cur95=$(eval "echo \$${label}95")
+	cur95=${cur95:=0}
+	cur99=$(eval "echo \$${label}99")
+	cur99=${cur99:=0}
+	if [ $curMax -lt $t ]; then
+		eval "${label}max=$t"
+	fi
+	if [ $curMin -gt $t ]; then
+		eval "${label}min=$t"
+	fi
+	((curSum=curSum+t))
+	eval "${label}sum=$curSum"
+
+	((curRestart=curRestart+${restart:=0}))
+	eval "${label}restart=$curRestart"
+	((curReclaim=curReclaim+${reclaim:=0}))
+	eval "${label}reclaim=$curReclaim"
+	((curFrames=curFrames+${frames:=0}))
+	eval "${label}frames=$curFrames"
+	((curJanks=curJanks+${janks:=0}))
+	eval "${label}janks=$curJanks"
+	((cur90=cur90+${l90:=0}))
+	eval "${label}90=$cur90"
+	((cur95=cur95+${l95:=0}))
+	eval "${label}95=$cur95"
+	((cur99=cur99+${l99:=0}))
+	eval "${label}99=$cur99"
+}
+function getStats {
+	label=$1
+	echo $(eval "echo \$${label}max") $(eval "echo \$${label}min") $(eval "echo \$${label}sum") \
+		$(eval "echo \$${label}restart") $(eval "echo \$${label}reclaim") \
+		$(eval "echo \$${label}frames") $(eval "echo \$${label}janks") \
+		$(eval "echo \$${label}90") $(eval "echo \$${label}95") $(eval "echo \$${label}99")
+}
+
+cur=1
+totaltime=0
+startTimestamp=$(date +"%s %N")
+
+while [ $cur -le $iterations ]
+do
+	if [ $iterations -gt 1 ]; then
+		echo =========================================
+		echo Iteration $cur of $iterations
+		echo =========================================
+	fi
+	if [ $iterations -gt 1 -o $cur -eq 1 ]; then
+		if [ $totaltimetest -eq 0 ]; then
+			printf "%-6s    %7s(ms)  %6s(ms) %s %s %s     %s\n" App  Time AmTime Restart DirReclaim Jank Latency
+		fi
+	fi
+
+	appnum=-1
+	for app in $appList
+	do
+		vout Starting $app...
+		((appnum=appnum+1))
+		loopTimestamp=$(date +"%s %N")
+		resetJankyFrames
+		resetJankyFrames $(getPackageName $app)
+		if [ $totaltimetest -eq 0 ]; then
+			tmpTraceOut="$tmpTraceOutBase-$app.out"
+			>$tmpTraceOut
+			startInstramentation
+		else
+			if [ $appnum -eq 0 ]; then
+				printf "%-8s %5s(ms) %3s(ms) %s      %s\n" App Start Iter Jank Latency
+			fi
+		fi
+		if [ $forcecoldstart -eq 0 ]; then
+			t=$(startActivity $app)
+		else
+			t=$(forceStartActivity $app)
+		fi
+
+		# let app finish drawing before checking janks
+		sleep $waitTime
+		set -- $(getJankyFrames $(getPackageName $app))
+		frames=$1
+		janks=$2
+		l90=$3
+		l95=$4
+		l99=$5
+		set -- $(getJankyFrames)
+		systemFrames=$1
+		systemJanks=$2
+		s90=$3
+		s95=$4
+		s99=$5
+		((frames=frames+systemFrames))
+		((janks=janks+systemJanks))
+		((l90=l90+s90))
+		((l95=l95+s95))
+		((l99=l99+s99))
+
+		loopEndTimestamp=$(date +"%s %N")
+		diffTime=$(computeTimeDiff $loopTimestamp $loopEndTimestamp)
+
+		if [ $frames -eq 0 ]; then
+			janks=0
+			jankPct=0
+		else
+			((jankPct=100*janks/frames))
+		fi
+		if [ $totaltimetest -gt 0 ]; then
+			# Note: using %f since %d doesn't work correctly
+			# when running on lollipop
+			printf "%-10s %5.0f   %5.0f    %4.0f(%2.0f%%) %2.0f/%2.0f/%2.0f\n" $app $t $diffTime $janks $jankPct $l90 $l95 $l99
+			((totaltime=totaltime+t))
+			continue
+		else
+			stopAndDumpInstramentation $tmpTraceOut
+			actName=$(getActivityName $app)
+			pkgName=$(getPackageName $app)
+			stime=$(getStartTime $actName $tmpTraceOut)
+			relaunch=$?
+			etime=$(getEndTime $pkgName $tmpTraceOut)
+			((tdiff=$etime-$stime))
+			if [ $etime -eq 0 -o $stime -eq 0 ]; then
+				handleError $app : could not compute start time stime=$stime  etime=$etime
+				# use AmTime so statistics make sense
+				tdiff=$t
+			fi
+			checkForDirectReclaim $actName $tmpTraceOut
+			directReclaim=$?
+
+			printf "%-12s %5d     %5d     %5d    %5d    %5d(%d%%) %d/%d/%d\n" "$app" "$tdiff" "$t" "$relaunch" "$directReclaim" "$janks" "$jankPct" $l90 $l95 $l99
+			computeStats "$app" "$tdiff" "$relaunch" "$directReclaim" "$frames" "$janks" $l90 $l95 $l99
+
+			if [ $savetmpfiles -eq 0 ]; then
+				rm -f $tmpTraceOut
+			fi
+		fi
+	done
+	((cur=cur+1))
+done
+endTimestamp=$(date +"%s %N")
+diffTime=$(computeTimeDiff $startTimestamp $endTimestamp)
+if [ $totaltimetest -gt 0 ]; then
+	printf "%-10s %5.0f   %5.0f\n" TOTAL $totaltime $diffTime
+fi
+
+if [ $iterations -gt 1 -a $totaltimetest -eq 0 ]; then
+	echo
+	echo =========================================
+	printf "Stats after $iterations iterations:\n"
+	echo =========================================
+	printf "%-6s    %7s(ms) %6s(ms) %6s(ms)    %s    %s %s     %s\n" App Max Ave Min Restart DirReclaim Jank Latency
+	for app in $appList
+	do
+		set -- $(getStats $app)
+		sum=$3
+		((ave=sum/iterations))
+		frames=$6
+		janks=$7
+		l90=$8
+		l95=$9
+		l99=${10}
+		((ave90=l90/iterations))
+		((ave95=l95/iterations))
+		((ave99=l99/iterations))
+		((jankPct=100*janks/frames))
+		printf "%-12s %5d      %5d      %5d      %5d      %5d     %5d(%d%%) %d/%d/%d\n" $app $1 $ave $2 $4 $5 $janks $jankPct $ave90 $ave95 $ave99
+	done
+fi