summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:32:58 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:32:58 -0800
commite16cb84e2324f05334d18dcf5956f20f44262b62 (patch)
treec87defa74181089778bc8e5671e2896d95d4e2b0
parent19ddb4b1680760e2d6863c3003976882ebd9d0fa (diff)
downloadextras-e16cb84e2324f05334d18dcf5956f20f44262b62.tar.gz
auto import from //depot/cupcake/@135843
-rw-r--r--Android.mk19
-rw-r--r--latencytop/Android.mk26
-rw-r--r--latencytop/MODULE_LICENSE_APACHE20
-rw-r--r--latencytop/NOTICE190
-rw-r--r--latencytop/latencytop.c442
-rw-r--r--libpagemap/Android.mk30
-rw-r--r--libpagemap/MODULE_LICENSE_APACHE20
-rw-r--r--libpagemap/NOTICE190
-rw-r--r--libpagemap/include/pagemap/pagemap.h171
-rw-r--r--libpagemap/pm_kernel.c158
-rw-r--r--libpagemap/pm_map.c125
-rw-r--r--libpagemap/pm_map.h24
-rw-r--r--libpagemap/pm_memusage.c28
-rw-r--r--libpagemap/pm_process.c290
-rw-r--r--librank/Android.mk30
-rw-r--r--librank/MODULE_LICENSE_APACHE20
-rw-r--r--librank/NOTICE190
-rw-r--r--librank/librank.c349
-rw-r--r--procmem/Android.mk30
-rw-r--r--procmem/MODULE_LICENSE_APACHE20
-rw-r--r--procmem/NOTICE190
-rw-r--r--procmem/procmem.c322
-rw-r--r--procrank/Android.mk30
-rw-r--r--procrank/MODULE_LICENSE_APACHE20
-rw-r--r--procrank/NOTICE190
-rw-r--r--procrank/procrank.c206
-rw-r--r--showmap/Android.mk13
-rw-r--r--showmap/MODULE_LICENSE_APACHE20
-rw-r--r--showmap/NOTICE190
-rw-r--r--showmap/showmap.c234
-rw-r--r--showslab/Android.mk15
-rw-r--r--showslab/MODULE_LICENSE_APACHE20
-rw-r--r--showslab/NOTICE190
-rw-r--r--showslab/showslab.c351
-rw-r--r--sound/Android.mk8
-rw-r--r--sound/playwav.c377
-rw-r--r--su/Android.mk15
-rw-r--r--su/MODULE_LICENSE_APACHE20
-rw-r--r--su/NOTICE190
-rw-r--r--su/su.c85
-rw-r--r--tests/Android.mk3
-rw-r--r--tests/bionic/libc/Android.mk140
-rw-r--r--tests/bionic/libc/MODULE_LICENSE_BSD_AND_GPL0
-rw-r--r--tests/bionic/libc/README.TXT32
-rw-r--r--tests/bionic/libc/bionic/lib_relocs.c19
-rw-r--r--tests/bionic/libc/bionic/test_cond.c97
-rw-r--r--tests/bionic/libc/bionic/test_getgrouplist.c58
-rw-r--r--tests/bionic/libc/bionic/test_mutex.c109
-rw-r--r--tests/bionic/libc/bionic/test_netinet_icmp.c8
-rw-r--r--tests/bionic/libc/bionic/test_pthread_cond.c83
-rw-r--r--tests/bionic/libc/bionic/test_pthread_create.c30
-rw-r--r--tests/bionic/libc/bionic/test_relocs.c25
-rw-r--r--tests/bionic/libc/common/hello_world.cpp8
-rw-r--r--tests/bionic/libc/common/test_gethostbyname.c53
-rw-r--r--tests/bionic/libc/common/test_gethostname.c20
-rw-r--r--tests/bionic/libc/common/test_libgen.c221
-rw-r--r--tests/bionic/libc/common/test_pthread_cleanup_push.c134
-rw-r--r--tests/bionic/libc/common/test_pthread_getcpuclockid.c86
-rw-r--r--tests/bionic/libc/common/test_pthread_join.c76
-rw-r--r--tests/bionic/libc/common/test_pthread_once.c82
-rw-r--r--tests/bionic/libc/common/test_semaphore.c129
-rw-r--r--tests/bionic/libc/common/test_seteuid.c57
-rw-r--r--tests/bionic/libc/common/test_static_cpp_mutex.cpp64
-rw-r--r--tests/bionic/libc/common/test_tm_zone.c55
-rw-r--r--tests/bionic/libc/common/test_udp.c121
-rw-r--r--tests/bionic/libc/glibc/assert/test-assert.c88
-rw-r--r--tests/bionic/libc/other/bench_locks.c32
-rw-r--r--tests/bionic/libc/other/test_aligned.c117
-rw-r--r--tests/bionic/libc/other/test_arc4random.c40
-rw-r--r--tests/bionic/libc/other/test_atomics.c17
-rw-r--r--tests/bionic/libc/other/test_jpeg.c362
-rw-r--r--tests/bionic/libc/other/test_sysconf.c137
-rw-r--r--tests/bionic/libc/other/test_system.c28
-rw-r--r--tests/bionic/libc/other/test_thread_max.c63
-rw-r--r--tests/bionic/libc/other/test_timer_create.c88
-rw-r--r--tests/bionic/libc/other/test_timer_create2.c100
-rw-r--r--tests/bionic/libc/other/test_timer_create3.c107
-rw-r--r--tests/bionic/libc/other/test_vfprintf_leak.c55
-rw-r--r--tests/bionic/libc/other/test_zlib.c267
-rw-r--r--tests/cpueater/Android.mk32
-rw-r--r--tests/cpueater/cpueater.c83
-rw-r--r--tests/cpueater/daemonize.c130
-rw-r--r--tests/framebuffer/Android.mk33
-rw-r--r--tests/framebuffer/fb_test.c232
-rw-r--r--tests/framebuffer/minui.h56
-rw-r--r--tests/framebuffer/refresh.c169
-rw-r--r--tests/fstest/Android.mk43
-rw-r--r--tests/fstest/README68
-rw-r--r--tests/fstest/perm_checker.c399
-rw-r--r--tests/fstest/perm_checker.conf165
-rw-r--r--tests/icachetest/Android.mk14
-rw-r--r--tests/icachetest/icache.S180
-rw-r--r--tests/icachetest/icache2.S170
-rw-r--r--tests/icachetest/icache_main.c34
-rw-r--r--tests/memtest/Android.mk19
-rw-r--r--tests/memtest/memtest.cpp763
-rw-r--r--tests/memtest/thumb.cpp27
-rw-r--r--tests/schedtest/Android.mk10
-rw-r--r--tests/schedtest/schedtest.c48
-rw-r--r--timeinfo/Android.mk24
-rw-r--r--timeinfo/timeinfo.cpp49
101 files changed, 10857 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 00000000..63185fac
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+ifneq ($(TARGET_SIMULATOR),true)
+ include $(all-subdir-makefiles)
+endif
diff --git a/latencytop/Android.mk b/latencytop/Android.mk
new file mode 100644
index 00000000..84bef410
--- /dev/null
+++ b/latencytop/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_SRC_FILES := latencytop.c
+
+LOCAL_MODULE := latencytop
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+
+LOCAL_MODULE_TAGS := debug tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/latencytop/MODULE_LICENSE_APACHE2 b/latencytop/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/latencytop/MODULE_LICENSE_APACHE2
diff --git a/latencytop/NOTICE b/latencytop/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/latencytop/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/latencytop/latencytop.c b/latencytop/latencytop.c
new file mode 100644
index 00000000..78d7c71d
--- /dev/null
+++ b/latencytop/latencytop.c
@@ -0,0 +1,442 @@
+/*
+ * 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 <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define MAX_LINE 512
+#define MAX_FILENAME 64
+
+const char *EXPECTED_VERSION = "Latency Top version : v0.1\n";
+const char *SYSCTL_FILE = "/proc/sys/kernel/latencytop";
+const char *GLOBAL_STATS_FILE = "/proc/latency_stats";
+const char *THREAD_STATS_FILE_FORMAT = "/proc/%d/task/%d/latency";
+
+struct latency_entry {
+ struct latency_entry *next;
+ unsigned long count;
+ unsigned long max;
+ unsigned long total;
+ char reason[MAX_LINE];
+};
+
+static inline void check_latencytop() { }
+
+static struct latency_entry *read_global_stats(struct latency_entry *list, int erase);
+static struct latency_entry *read_process_stats(struct latency_entry *list, int erase, int pid);
+static struct latency_entry *read_thread_stats(struct latency_entry *list, int erase, int pid, int tid, int fatal);
+
+static struct latency_entry *alloc_latency_entry(void);
+static void free_latency_entry(struct latency_entry *e);
+
+static void set_latencytop(int on);
+static struct latency_entry *read_latency_file(FILE *f, struct latency_entry *list);
+static void erase_latency_file(FILE *f);
+
+static struct latency_entry *find_latency_entry(struct latency_entry *e, char *reason);
+static void print_latency_entries(struct latency_entry *head);
+
+static void signal_handler(int sig);
+static void disable_latencytop(void);
+
+static int numcmp(const long long a, const long long b);
+static int lat_cmp(const void *a, const void *b);
+
+static void clear_screen(void);
+static void usage(const char *cmd);
+
+struct latency_entry *free_entries;
+
+int main(int argc, char *argv[]) {
+ struct latency_entry *e;
+ int delay, iterations;
+ int pid, tid;
+ int count, erase;
+ int i;
+
+ delay = 1;
+ iterations = 0;
+ pid = tid = 0;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-d")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -d expects an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ delay = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-n")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -n expects an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ iterations = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-h")) {
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ }
+ if (!strcmp(argv[i], "-p")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -p expects an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ pid = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-t")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -t expects an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ tid = atoi(argv[++i]);
+ continue;
+ }
+ fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (tid && !pid) {
+ fprintf(stderr, "If you provide a thread ID with -t, you must provide a process ID with -p.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ check_latencytop();
+
+ free_entries = NULL;
+
+ signal(SIGINT, &signal_handler);
+ signal(SIGTERM, &signal_handler);
+
+ atexit(&disable_latencytop);
+
+ set_latencytop(1);
+
+ count = 0;
+ erase = 1;
+
+ while ((iterations == 0) || (count++ < iterations)) {
+
+ sleep(delay);
+
+ e = NULL;
+ if (pid) {
+ if (tid) {
+ e = read_thread_stats(e, erase, pid, tid, 1);
+ } else {
+ e = read_process_stats(e, erase, pid);
+ }
+ } else {
+ e = read_global_stats(e, erase);
+ }
+ erase = 0;
+
+ clear_screen();
+ if (pid) {
+ if (tid) {
+ printf("Latencies for thread %d in process %d:\n", tid, pid);
+ } else {
+ printf("Latencies for process %d:\n", pid);
+ }
+ } else {
+ printf("Latencies across all processes:\n");
+ }
+ print_latency_entries(e);
+ }
+
+ set_latencytop(0);
+
+ return 0;
+}
+
+static struct latency_entry *read_global_stats(struct latency_entry *list, int erase) {
+ FILE *f;
+ struct latency_entry *e;
+
+ if (erase) {
+ f = fopen(GLOBAL_STATS_FILE, "w");
+ if (!f) {
+ fprintf(stderr, "Could not open global latency stats file: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ fprintf(f, "erase\n");
+ fclose(f);
+ }
+
+ f = fopen(GLOBAL_STATS_FILE, "r");
+ if (!f) {
+ fprintf(stderr, "Could not open global latency stats file: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ e = read_latency_file(f, list);
+
+ fclose(f);
+
+ return e;
+}
+
+static struct latency_entry *read_process_stats(struct latency_entry *list, int erase, int pid) {
+ char dirname[MAX_FILENAME];
+ DIR *dir;
+ struct dirent *ent;
+ struct latency_entry *e;
+ int tid;
+
+ sprintf(dirname, "/proc/%d/task", pid);
+ dir = opendir(dirname);
+ if (!dir) {
+ fprintf(stderr, "Could not open task dir for process %d.\n", pid);
+ fprintf(stderr, "Perhaps the process has terminated?\n");
+ exit(EXIT_FAILURE);
+ }
+
+ e = list;
+ while ((ent = readdir(dir))) {
+ if (!isdigit(ent->d_name[0]))
+ continue;
+
+ tid = atoi(ent->d_name);
+
+ e = read_thread_stats(e, erase, pid, tid, 0);
+ }
+
+ closedir(dir);
+
+ return e;
+}
+
+static struct latency_entry *read_thread_stats(struct latency_entry *list, int erase, int pid, int tid, int fatal) {
+ char filename[MAX_FILENAME];
+ FILE *f;
+ struct latency_entry *e;
+
+ sprintf(filename, THREAD_STATS_FILE_FORMAT, pid, tid);
+
+ if (erase) {
+ f = fopen(filename, "w");
+ if (!f) {
+ if (fatal) {
+ fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
+ fprintf(stderr, "Perhaps the process or thread has terminated?\n");
+ exit(EXIT_FAILURE);
+ } else {
+ return list;
+ }
+ }
+ fprintf(f, "erase\n");
+ fclose(f);
+ }
+
+ f = fopen(GLOBAL_STATS_FILE, "r");
+ if (!f) {
+ if (fatal) {
+ fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
+ fprintf(stderr, "Perhaps the process or thread has terminated?\n");
+ exit(EXIT_FAILURE);
+ } else {
+ return list;
+ }
+ }
+
+ e = read_latency_file(f, list);
+
+ fclose(f);
+
+ return e;
+}
+
+static struct latency_entry *alloc_latency_entry(void) {
+ struct latency_entry *e;
+
+ if (free_entries) {
+ e = free_entries;
+ free_entries = free_entries->next;
+ } else {
+ e = calloc(1, sizeof(struct latency_entry));
+ if (!e) {
+ fprintf(stderr, "Could not allocate latency entry: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ return e;
+}
+
+static void free_latency_entry(struct latency_entry *e) {
+ e->next = free_entries;
+ free_entries = e;
+}
+
+static struct latency_entry *find_latency_entry(struct latency_entry *head, char *reason) {
+ struct latency_entry *e;
+
+ e = head;
+
+ while (e) {
+ if (!strcmp(e->reason, reason))
+ return e;
+ e = e->next;
+ }
+
+ return NULL;
+}
+
+static void set_latencytop(int on) {
+ FILE *f;
+
+ f = fopen(SYSCTL_FILE, "w");
+ if (!f) {
+ fprintf(stderr, "Could not open %s: %s\n", SYSCTL_FILE, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(f, "%d\n", on);
+
+ fclose(f);
+}
+
+static void erase_latency_file(FILE *f) {
+ fprintf(f, "erase\n");
+}
+
+static struct latency_entry *read_latency_file(FILE *f, struct latency_entry *list) {
+ struct latency_entry *e, *head;
+ char line[MAX_LINE];
+ unsigned long count, max, total;
+ char reason[MAX_LINE];
+
+ head = list;
+
+ if (!fgets(line, MAX_LINE, f)) {
+ fprintf(stderr, "Could not read latency file version: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (strcmp(line, EXPECTED_VERSION) != 0) {
+ fprintf(stderr, "Expected version: %s\n", EXPECTED_VERSION);
+ fprintf(stderr, "But got version: %s", line);
+ exit(EXIT_FAILURE);
+ }
+
+ while (fgets(line, MAX_LINE, f)) {
+ sscanf(line, "%ld %ld %ld %s", &count, &total, &max, reason);
+ if (max > 0 || total > 0) {
+ e = find_latency_entry(head, reason);
+ if (e) {
+ e->count += count;
+ if (max > e->max)
+ e->max = max;
+ e->total += total;
+ } else {
+ e = alloc_latency_entry();
+ e->count = count;
+ e->max = max;
+ e->total = total;
+ strcpy(e->reason, reason);
+ e->next = head;
+ head = e;
+ }
+ }
+ }
+
+ return head;
+}
+
+static void print_latency_entries(struct latency_entry *head) {
+ struct latency_entry *e, **array;
+ unsigned long average;
+ int i, count;
+
+ e = head;
+ count = 0;
+ while (e) {
+ count++;
+ e = e->next;
+ }
+
+ e = head;
+ array = calloc(count, sizeof(struct latency_entry *));
+ if (!array) {
+ fprintf(stderr, "Error allocating array: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ for (i = 0; i < count; i++) {
+ array[i] = e;
+ e = e->next;
+ }
+
+ qsort(array, count, sizeof(struct latency_entry *), &lat_cmp);
+
+ printf("%10s %10s %7s %s\n", "Maximum", "Average", "Count", "Reason");
+ for (i = 0; i < count; i++) {
+ e = array[i];
+ average = e->total / e->count;
+ printf("%4lu.%02lu ms %4lu.%02lu ms %7ld %s\n",
+ e->max / 1000, (e->max % 1000) / 10,
+ average / 1000, (average % 1000) / 10,
+ e->count,
+ e->reason);
+ }
+
+ free(array);
+}
+
+static void signal_handler(int sig) {
+ exit(EXIT_SUCCESS);
+}
+
+static void disable_latencytop(void) {
+ set_latencytop(0);
+}
+
+static void clear_screen(void) {
+ printf("\n\n");
+}
+
+static void usage(const char *cmd) {
+ fprintf(stderr, "Usage: %s [ -d delay ] [ -n iterations ] [ -p pid [ -t tid ] ] [ -h ]\n"
+ " -d delay Time to sleep between updates.\n"
+ " -n iterations Number of updates to show (0 = infinite).\n"
+ " -p pid Process to monitor (default is all).\n"
+ " -t tid Thread (within specified process) to monitor (default is all).\n"
+ " -h Display this help screen.\n",
+ cmd);
+}
+
+static int numcmp(const long long a, const long long b) {
+ if (a < b) return -1;
+ if (a > b) return 1;
+ return 0;
+}
+
+static int lat_cmp(const void *a, const void *b) {
+ const struct latency_entry *pa, *pb;
+
+ pa = (*((struct latency_entry **)a));
+ pb = (*((struct latency_entry **)b));
+
+ return numcmp(pb->max, pa->max);
+}
diff --git a/libpagemap/Android.mk b/libpagemap/Android.mk
new file mode 100644
index 00000000..b38363c8
--- /dev/null
+++ b/libpagemap/Android.mk
@@ -0,0 +1,30 @@
+# 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 := libpagemap
+LOCAL_MODULE_TAGS := debug
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_SRC_FILES := \
+ pm_kernel.c \
+ pm_process.c \
+ pm_map.c \
+ pm_memusage.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libpagemap/MODULE_LICENSE_APACHE2 b/libpagemap/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/libpagemap/MODULE_LICENSE_APACHE2
diff --git a/libpagemap/NOTICE b/libpagemap/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/libpagemap/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/libpagemap/include/pagemap/pagemap.h b/libpagemap/include/pagemap/pagemap.h
new file mode 100644
index 00000000..09ff29d8
--- /dev/null
+++ b/libpagemap/include/pagemap/pagemap.h
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#ifndef _PAGEMAP_PAGEMAP_H
+#define _PAGEMAP_PAGEMAP_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+typedef struct pm_memusage pm_memusage_t;
+
+/* Holds the various metrics for memory usage of a process or a mapping. */
+struct pm_memusage {
+ size_t vss;
+ size_t rss;
+ size_t pss;
+ size_t uss;
+};
+
+/* Clears a memusage. */
+void pm_memusage_zero(pm_memusage_t *mu);
+/* Adds one memusage (a) to another (b). */
+void pm_memusage_add(pm_memusage_t *a, pm_memusage_t *b);
+
+typedef struct pm_kernel pm_kernel_t;
+typedef struct pm_process pm_process_t;
+typedef struct pm_map pm_map_t;
+
+/* pm_kernel_t holds the state necessary to interface to the kernel's pagemap
+ * system on a global level. */
+struct pm_kernel {
+ int kpagecount_fd;
+ int kpageflags_fd;
+
+ int pagesize;
+};
+
+/* pm_process_t holds the state necessary to interface to a particular process'
+ * pagemap. */
+struct pm_process {
+ pm_kernel_t *ker;
+
+ pid_t pid;
+
+ pm_map_t **maps;
+ int num_maps;
+
+ int pagemap_fd;
+};
+
+/* pm_map_t holds the state necessary to access information about a particular
+ * mapping in a particular process. */
+struct pm_map {
+ pm_process_t *proc;
+
+ unsigned long start;
+ unsigned long end;
+ unsigned long offset;
+ int flags;
+
+ char *name;
+};
+
+/* Create a pm_kernel_t. */
+int pm_kernel_create(pm_kernel_t **ker_out);
+
+#define pm_kernel_pagesize(ker) ((ker)->pagesize)
+
+/* Get a list of probably-existing PIDs (returned through *pids_out).
+ * Length of the array (in sizeof(pid_t) units) is returned through *len.
+ * The array should be freed by the caller. */
+int pm_kernel_pids(pm_kernel_t *ker, pid_t **pids_out, size_t *len);
+
+/* Get the map count (from /proc/kpagecount) of a physical frame.
+ * The count is returned through *count_out. */
+int pm_kernel_count(pm_kernel_t *ker, unsigned long pfn, uint64_t *count_out);
+
+/* Get the page flags (from /proc/kpageflags) of a physical frame.
+ * The count is returned through *flags_out. */
+int pm_kernel_flags(pm_kernel_t *ker, unsigned long pfn, uint64_t *flags_out);
+
+#define PM_PAGE_LOCKED (1 << 0)
+#define PM_PAGE_ERROR (1 << 1)
+#define PM_PAGE_REFERENCED (1 << 2)
+#define PM_PAGE_UPTODATE (1 << 3)
+#define PM_PAGE_DIRTY (1 << 4)
+#define PM_PAGE_LRU (1 << 5)
+#define PM_PAGE_ACTIVE (1 << 6)
+#define PM_PAGE_SLAB (1 << 7)
+#define PM_PAGE_WRITEBACK (1 << 8)
+#define PM_PAGE_RECLAIM (1 << 9)
+#define PM_PAGE_BUDDY (1 << 10)
+
+/* Destroy a pm_kernel_t. */
+int pm_kernel_destroy(pm_kernel_t *ker);
+
+/* Get the PID of a pm_process_t. */
+#define pm_process_pid(proc) ((proc)->pid)
+
+/* Create a pm_process_t and returns it through *proc_out.
+ * Takes a pm_kernel_t, and the PID of the process. */
+int pm_process_create(pm_kernel_t *ker, pid_t pid, pm_process_t **proc_out);
+
+/* Get the total memory usage of a process and store in *usage_out. */
+int pm_process_usage(pm_process_t *proc, pm_memusage_t *usage_out);
+
+/* Get the working set of a process (if ws_out != NULL), and reset it
+ * (if reset != 0). */
+int pm_process_workingset(pm_process_t *proc, pm_memusage_t *ws_out, int reset);
+
+/* Get the PFNs corresponding to a range of virtual addresses.
+ * The array of PFNs is returned through *range_out, and the caller has the
+ * responsibility to free it. */
+int pm_process_pagemap_range(pm_process_t *proc,
+ unsigned long low, unsigned long hi,
+ uint64_t **range_out, size_t *len);
+
+#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << ((bits) + 1)) - 1))
+
+#define PM_PAGEMAP_PRESENT(x) (_BITS(x, 63, 1))
+#define PM_PAGEMAP_SWAPPED(x) (!_BITS(x, 62, 1))
+#define PM_PAGEMAP_SHIFT(x) (_BITS(x, 55, 6))
+#define PM_PAGEMAP_PFN(x) (_BITS(x, 0, 55))
+#define PM_PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
+#define PM_PAGEMAP_SWAP_TYPE(x) (_BITS(x, 0, 5))
+
+/* Get the maps in the virtual address space of this process.
+ * Returns an array of pointers to pm_map_t through *maps.
+ * The array should be freed by the caller, but the maps should not be
+ * modified or destroyed. */
+int pm_process_maps(pm_process_t *proc, pm_map_t ***maps_out, size_t *len);
+
+/* Destroy a pm_process_t. */
+int pm_process_destroy(pm_process_t *proc);
+
+/* Get the name, flags, start/end address, or offset of a map. */
+#define pm_map_name(map) ((map)->name)
+#define pm_map_flags(map) ((map)->flags)
+#define PM_MAP_READ 1
+#define PM_MAP_WRITE 2
+#define PM_MAP_EXEC 4
+#define pm_map_start(map) ((map)->start)
+#define pm_map_end(map) ((map)->end)
+#define pm_map_offset(map) ((map)->offset)
+
+/* Get the PFNs of the pages in the virtual address space of this map.
+ * Array of PFNs is returned through *pagemap_out, and should be freed by the
+ * caller. */
+int pm_map_pagemap(pm_map_t *map, uint64_t **pagemap_out, size_t *len);
+
+/* Get the memory usage of this map alone. */
+int pm_map_usage(pm_map_t *map, pm_memusage_t *usage_out);
+
+/* Get the working set of this map alone. */
+int pm_map_workingset(pm_map_t *map, pm_memusage_t *ws_out);
+
+#endif
diff --git a/libpagemap/pm_kernel.c b/libpagemap/pm_kernel.c
new file mode 100644
index 00000000..3615f1ac
--- /dev/null
+++ b/libpagemap/pm_kernel.c
@@ -0,0 +1,158 @@
+/*
+ * 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <pagemap/pagemap.h>
+
+int pm_kernel_create(pm_kernel_t **ker_out) {
+ pm_kernel_t *ker;
+ int error;
+
+ if (!ker_out)
+ return 1;
+
+ ker = calloc(1, sizeof(*ker));
+ if (!ker)
+ return errno;
+
+ ker->kpagecount_fd = open("/proc/kpagecount", O_RDONLY);
+ if (ker->kpagecount_fd < 0) {
+ error = errno;
+ free(ker);
+ return error;
+ }
+
+ ker->kpageflags_fd = open("/proc/kpageflags", O_RDONLY);
+ if (ker->kpageflags_fd < 0) {
+ error = errno;
+ close(ker->kpagecount_fd);
+ free(ker);
+ return error;
+ }
+
+ ker->pagesize = getpagesize();
+
+ *ker_out = ker;
+
+ return 0;
+}
+
+#define INIT_PIDS 20
+int pm_kernel_pids(pm_kernel_t *ker, pid_t **pids_out, size_t *len) {
+ DIR *proc;
+ struct dirent *dir;
+ pid_t pid, *pids, *new_pids;
+ size_t pids_count, pids_size;
+ int error;
+
+ proc = opendir("/proc");
+ if (!proc)
+ return errno;
+
+ pids = malloc(INIT_PIDS * sizeof(pid_t));
+ if (!pids) {
+ closedir(proc);
+ return errno;
+ }
+ pids_count = 0; pids_size = INIT_PIDS;
+
+ while ((dir = readdir(proc))) {
+ if (sscanf(dir->d_name, "%d", &pid) < 1)
+ continue;
+
+ if (pids_count >= pids_size) {
+ new_pids = realloc(pids, 2 * pids_size * sizeof(pid_t));
+ if (!new_pids) {
+ error = errno;
+ free(pids);
+ closedir(proc);
+ return error;
+ }
+ pids = new_pids;
+ pids_size = 2 * pids_size;
+ }
+
+ pids[pids_count] = pid;
+
+ pids_count++;
+ }
+
+ closedir(proc);
+
+ new_pids = realloc(pids, pids_count * sizeof(pid_t));
+ if (!new_pids) {
+ error = errno;
+ free(pids);
+ return error;
+ }
+
+ *pids_out = new_pids;
+ *len = pids_count;
+
+ return 0;
+}
+
+int pm_kernel_count(pm_kernel_t *ker, unsigned long pfn, uint64_t *count_out) {
+ off_t off;
+
+ if (!ker || !count_out)
+ return -1;
+
+ off = lseek(ker->kpagecount_fd, pfn * sizeof(uint64_t), SEEK_SET);
+ if (off == (off_t)-1)
+ return errno;
+ if (read(ker->kpagecount_fd, count_out, sizeof(uint64_t)) <
+ (ssize_t)sizeof(uint64_t))
+ return errno;
+
+ return 0;
+}
+
+int pm_kernel_flags(pm_kernel_t *ker, unsigned long pfn, uint64_t *flags_out) {
+ off_t off;
+
+ if (!ker || !flags_out)
+ return -1;
+
+ off = lseek(ker->kpageflags_fd, pfn * sizeof(uint64_t), SEEK_SET);
+ if (off == (off_t)-1)
+ return errno;
+ if (read(ker->kpageflags_fd, flags_out, sizeof(uint64_t)) <
+ (ssize_t)sizeof(uint64_t))
+ return errno;
+
+ return 0;
+}
+
+int pm_kernel_destroy(pm_kernel_t *ker) {
+ if (!ker)
+ return -1;
+
+ close(ker->kpagecount_fd);
+ close(ker->kpageflags_fd);
+
+ free(ker);
+
+ return 0;
+}
diff --git a/libpagemap/pm_map.c b/libpagemap/pm_map.c
new file mode 100644
index 00000000..f683ba6c
--- /dev/null
+++ b/libpagemap/pm_map.c
@@ -0,0 +1,125 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <pagemap/pagemap.h>
+
+int pm_map_pagemap(pm_map_t *map, uint64_t **pagemap_out, size_t *len) {
+ if (!map)
+ return -1;
+
+ return pm_process_pagemap_range(map->proc, map->start, map->end,
+ pagemap_out, len);
+}
+
+int pm_map_usage(pm_map_t *map, pm_memusage_t *usage_out) {
+ uint64_t *pagemap;
+ size_t len, i;
+ uint64_t count;
+ pm_memusage_t usage;
+ int error;
+
+ if (!map || !usage_out)
+ return -1;
+
+ error = pm_map_pagemap(map, &pagemap, &len);
+ if (error) return error;
+
+ pm_memusage_zero(&usage);
+
+ for (i = 0; i < len; i++) {
+ if (!PM_PAGEMAP_PRESENT(pagemap[i]) ||
+ PM_PAGEMAP_SWAPPED(pagemap[i]))
+ continue;
+
+ error = pm_kernel_count(map->proc->ker, PM_PAGEMAP_PFN(pagemap[i]),
+ &count);
+ if (error) goto out;
+
+ usage.vss += map->proc->ker->pagesize;
+ usage.rss += (count >= 1) ? (map->proc->ker->pagesize) : (0);
+ usage.pss += (count >= 1) ? (map->proc->ker->pagesize / count) : (0);
+ usage.uss += (count == 1) ? (map->proc->ker->pagesize) : (0);
+ }
+
+ memcpy(usage_out, &usage, sizeof(usage));
+
+ error = 0;
+
+out:
+ free(pagemap);
+
+ return error;
+}
+
+int pm_map_workingset(pm_map_t *map, pm_memusage_t *ws_out) {
+ uint64_t *pagemap;
+ size_t len, i;
+ uint64_t count, flags;
+ pm_memusage_t ws;
+ int error;
+
+ if (!map || !ws_out)
+ return -1;
+
+ error = pm_map_pagemap(map, &pagemap, &len);
+ if (error) return error;
+
+ pm_memusage_zero(&ws);
+
+ for (i = 0; i < len; i++) {
+ if (!PM_PAGEMAP_PRESENT(pagemap[i]) ||
+ PM_PAGEMAP_SWAPPED(pagemap[i]))
+ continue;
+
+ error = pm_kernel_flags(map->proc->ker, PM_PAGEMAP_PFN(pagemap[i]),
+ &flags);
+ if (error) goto out;
+
+ if (!(flags & PM_PAGE_REFERENCED))
+ continue;
+
+ error = pm_kernel_count(map->proc->ker, PM_PAGEMAP_PFN(pagemap[i]),
+ &count);
+ if (error) goto out;
+
+ ws.vss += map->proc->ker->pagesize;
+ ws.rss += (count >= 1) ? (map->proc->ker->pagesize) : (0);
+ ws.pss += (count >= 1) ? (map->proc->ker->pagesize / count) : (0);
+ ws.uss += (count == 1) ? (map->proc->ker->pagesize) : (0);
+ }
+
+ memcpy(ws_out, &ws, sizeof(ws));
+
+ error = 0;
+
+out:
+ free(pagemap);
+
+ return 0;
+}
+
+int pm_map_destroy(pm_map_t *map) {
+ if (!map)
+ return -1;
+
+ free(map->name);
+ free(map);
+
+ return 0;
+}
diff --git a/libpagemap/pm_map.h b/libpagemap/pm_map.h
new file mode 100644
index 00000000..08dc4485
--- /dev/null
+++ b/libpagemap/pm_map.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBS_PAGEMAP_PM_MAP_H
+#define _LIBS_PAGEMAP_PM_MAP_H
+
+#include <pagemap/pagemap.h>
+
+int pm_map_destroy(pm_map_t *map);
+
+#endif
diff --git a/libpagemap/pm_memusage.c b/libpagemap/pm_memusage.c
new file mode 100644
index 00000000..9c5db92e
--- /dev/null
+++ b/libpagemap/pm_memusage.c
@@ -0,0 +1,28 @@
+/*
+ * 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 <pagemap/pagemap.h>
+
+void pm_memusage_zero(pm_memusage_t *mu) {
+ mu->vss = mu->rss = mu->pss = mu->uss = 0;
+}
+
+void pm_memusage_add(pm_memusage_t *a, pm_memusage_t *b) {
+ a->vss += b->vss;
+ a->rss += b->rss;
+ a->pss += b->pss;
+ a->uss += b->uss;
+}
diff --git a/libpagemap/pm_process.c b/libpagemap/pm_process.c
new file mode 100644
index 00000000..1ab367d8
--- /dev/null
+++ b/libpagemap/pm_process.c
@@ -0,0 +1,290 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <pagemap/pagemap.h>
+
+#include "pm_map.h"
+
+static int read_maps(pm_process_t *proc);
+
+#define MAX_FILENAME 64
+
+int pm_process_create(pm_kernel_t *ker, pid_t pid, pm_process_t **proc_out) {
+ pm_process_t *proc;
+ char filename[MAX_FILENAME];
+ int error;
+
+ if (!ker || !proc_out)
+ return -1;
+
+ proc = calloc(1, sizeof(*proc));
+ if (!proc)
+ return errno;
+
+ proc->ker = ker;
+ proc->pid = pid;
+
+ error = snprintf(filename, MAX_FILENAME, "/proc/%d/pagemap", pid);
+ if (error < 0 || error >= MAX_FILENAME) {
+ error = (error < 0) ? (errno) : (-1);
+ free(proc);
+ return error;
+ }
+
+ proc->pagemap_fd = open(filename, O_RDONLY);
+ if (proc->pagemap_fd < 0) {
+ error = errno;
+ free(proc);
+ return error;
+ }
+
+ error = read_maps(proc);
+ if (error) {
+ free(proc);
+ return error;
+ }
+
+ *proc_out = proc;
+
+ return 0;
+}
+
+int pm_process_usage(pm_process_t *proc, pm_memusage_t *usage_out) {
+ pm_memusage_t usage, map_usage;
+ int error;
+ int i;
+
+ if (!proc || !usage_out)
+ return -1;
+
+ pm_memusage_zero(&usage);
+
+ for (i = 0; i < proc->num_maps; i++) {
+ error = pm_map_usage(proc->maps[i], &map_usage);
+ if (error) return error;
+
+ pm_memusage_add(&usage, &map_usage);
+ }
+
+ memcpy(usage_out, &usage, sizeof(pm_memusage_t));
+
+ return 0;
+}
+
+int pm_process_pagemap_range(pm_process_t *proc,
+ unsigned long low, unsigned long high,
+ uint64_t **range_out, size_t *len) {
+ int firstpage, numpages;
+ uint64_t *range;
+ off_t off;
+ int error;
+
+ if (!proc || (low >= high) || !range_out || !len)
+ return -1;
+
+ firstpage = low / proc->ker->pagesize;
+ numpages = (high - low) / proc->ker->pagesize;
+
+ range = malloc(numpages * sizeof(uint64_t));
+ if (!range)
+ return errno;
+
+ off = lseek(proc->pagemap_fd, firstpage * sizeof(uint64_t), SEEK_SET);
+ if (off == (off_t)-1) {
+ error = errno;
+ free(range);
+ return error;
+ }
+ error = read(proc->pagemap_fd, (char*)range, numpages * sizeof(uint64_t));
+ if (error < numpages * sizeof(uint64_t)) {
+ error = (error < 0) ? errno : -1;
+ free(range);
+ return error;
+ }
+
+ *range_out = range;
+ *len = numpages;
+
+ return 0;
+}
+
+int pm_process_maps(pm_process_t *proc, pm_map_t ***maps_out, size_t *len) {
+ pm_map_t **maps;
+
+ if (!proc || !maps_out || !len)
+ return -1;
+
+ if (proc->num_maps) {
+ maps = malloc(proc->num_maps * sizeof(pm_map_t*));
+ if (!maps)
+ return errno;
+
+ memcpy(maps, proc->maps, proc->num_maps * sizeof(pm_map_t*));
+
+ *maps_out = maps;
+ } else {
+ *maps_out = NULL;
+ }
+ *len = proc->num_maps;
+
+ return 0;
+}
+
+int pm_process_workingset(pm_process_t *proc,
+ pm_memusage_t *ws_out, int reset) {
+ pm_memusage_t ws, map_ws;
+ char filename[MAX_FILENAME];
+ int fd;
+ int i, j;
+ int error;
+
+ if (!proc)
+ return -1;
+
+ if (ws_out) {
+ pm_memusage_zero(&ws);
+ for (i = 0; i < proc->num_maps; i++) {
+ error = pm_map_workingset(proc->maps[i], &map_ws);
+ if (error) return error;
+
+ pm_memusage_add(&ws, &map_ws);
+ }
+
+ memcpy(ws_out, &ws, sizeof(ws));
+ }
+
+ if (reset) {
+ error = snprintf(filename, MAX_FILENAME, "/proc/%d/clear_refs",
+ proc->pid);
+ if (error < 0 || error >= MAX_FILENAME) {
+ return (error < 0) ? (errno) : (-1);
+ }
+
+ fd = open(filename, O_WRONLY);
+ if (fd < 0)
+ return errno;
+
+ write(fd, "1\n", strlen("1\n"));
+
+ close(fd);
+ }
+
+ return 0;
+}
+
+int pm_process_destroy(pm_process_t *proc) {
+ if (!proc)
+ return -1;
+
+ free(proc->maps);
+ close(proc->pagemap_fd);
+ free(proc);
+
+ return 0;
+}
+
+#define INITIAL_MAPS 10
+#define MAX_LINE 256
+#define MAX_PERMS 5
+
+/*
+ * #define FOO 123
+ * S(FOO) => "123"
+ */
+#define _S(n) #n
+#define S(n) _S(n)
+
+static int read_maps(pm_process_t *proc) {
+ char filename[MAX_FILENAME];
+ char line[MAX_LINE], name[MAX_LINE], perms[MAX_PERMS];
+ FILE *maps_f;
+ pm_map_t *map, **maps, **new_maps;
+ int maps_count, maps_size;
+ int error;
+
+ if (!proc)
+ return -1;
+
+ maps = calloc(INITIAL_MAPS, sizeof(pm_map_t*));
+ if (!maps)
+ return errno;
+ maps_count = 0; maps_size = INITIAL_MAPS;
+
+ error = snprintf(filename, MAX_FILENAME, "/proc/%d/maps", proc->pid);
+ if (error < 0 || error >= MAX_FILENAME)
+ return (error < 0) ? (errno) : (-1);
+
+ maps_f = fopen(filename, "r");
+ if (!maps_f)
+ return errno;
+
+ while (fgets(line, MAX_LINE, maps_f)) {
+ if (maps_count >= maps_size) {
+ new_maps = realloc(maps, 2 * maps_size * sizeof(pm_map_t*));
+ if (!new_maps) {
+ error = errno;
+ free(maps);
+ fclose(maps_f);
+ return error;
+ }
+ maps = new_maps;
+ maps_size *= 2;
+ }
+
+ maps[maps_count] = map = calloc(1, sizeof(*map));
+
+ map->proc = proc;
+
+ sscanf(line, "%lx-%lx %s %lx %*s %*d %" S(MAX_LINE) "s",
+ &map->start, &map->end, perms, &map->offset, name);
+
+ map->name = malloc(strlen(name) + 1);
+ if (!map->name) {
+ error = errno;
+ for (; maps_count > 0; maps_count--)
+ pm_map_destroy(maps[maps_count]);
+ free(maps);
+ return error;
+ }
+ strcpy(map->name, name);
+ if (perms[0] == 'r') map->flags |= PM_MAP_READ;
+ if (perms[1] == 'w') map->flags |= PM_MAP_WRITE;
+ if (perms[2] == 'x') map->flags |= PM_MAP_EXEC;
+
+ maps_count++;
+ }
+
+ fclose(maps_f);
+
+ new_maps = realloc(maps, maps_count * sizeof(pm_map_t*));
+ if (maps_count && !new_maps) {
+ error = errno;
+ free(maps);
+ return error;
+ }
+
+ proc->maps = new_maps;
+ proc->num_maps = maps_count;
+
+ return 0;
+}
diff --git a/librank/Android.mk b/librank/Android.mk
new file mode 100644
index 00000000..300b3f59
--- /dev/null
+++ b/librank/Android.mk
@@ -0,0 +1,30 @@
+# 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_SRC_FILES := librank.c
+
+LOCAL_C_INCLUDES := $(call include-path-for, libpagemap)
+
+LOCAL_SHARED_LIBRARIES := libpagemap
+
+LOCAL_MODULE := librank
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+
+LOCAL_MODULE_TAGS := debug
+
+include $(BUILD_EXECUTABLE)
diff --git a/librank/MODULE_LICENSE_APACHE2 b/librank/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/librank/MODULE_LICENSE_APACHE2
diff --git a/librank/NOTICE b/librank/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/librank/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/librank/librank.c b/librank/librank.c
new file mode 100644
index 00000000..13b20974
--- /dev/null
+++ b/librank/librank.c
@@ -0,0 +1,349 @@
+/*
+ * 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 <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <pagemap/pagemap.h>
+
+#define MAX_CMDLINE 256
+
+struct process_info {
+ pid_t pid;
+ char cmdline[MAX_CMDLINE];
+};
+
+struct mapping_info {
+ struct process_info *proc;
+ pm_memusage_t usage;
+};
+
+struct library_info {
+ struct library_info *next;
+ char *name;
+ struct mapping_info **mappings;
+ int mappings_count;
+ int mappings_size;
+ pm_memusage_t total_usage;
+};
+
+static void usage(char *myname);
+static int getprocname(pid_t pid, char *buf, size_t len);
+static int numcmp(long long a, long long b);
+static int licmp(const void *a, const void *b);
+
+char *library_name_blacklist[] = { "[heap]", "[stack]", "", NULL };
+
+#define declare_sort(field) \
+ static int sort_by_ ## field (const void *a, const void *b)
+
+declare_sort(vss);
+declare_sort(rss);
+declare_sort(pss);
+declare_sort(uss);
+
+#define INIT_LIBRARIES 16
+#define INIT_MAPPINGS 4
+
+static int order;
+
+struct library_info **libraries;
+int libraries_count;
+int libraries_size;
+
+struct library_info *get_library(char *name) {
+ int i;
+ struct library_info *library;
+
+ for (i = 0; library_name_blacklist[i]; i++)
+ if (!strcmp(name, library_name_blacklist[i]))
+ return NULL;
+
+ for (i = 0; i < libraries_count; i++) {
+ if (!strcmp(libraries[i]->name, name))
+ return libraries[i];
+ }
+
+ if (libraries_count >= libraries_size) {
+ libraries = realloc(libraries, 2 * libraries_size * sizeof(struct library_info *));
+ if (!libraries) {
+ fprintf(stderr, "Couldn't resize libraries array: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ libraries_size = 2 * libraries_size;
+ }
+
+ library = calloc(1, sizeof(*library));
+ if (!library) {
+ fprintf(stderr, "Couldn't allocate space for library struct: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ library->name = malloc(strlen(name) + 1);
+ if (!library->name) {
+ fprintf(stderr, "Couldn't allocate space for library name: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ strcpy(library->name, name);
+ library->mappings = malloc(INIT_MAPPINGS * sizeof(struct mapping_info *));
+ if (!library->mappings) {
+ fprintf(stderr, "Couldn't allocate space for library mappings array: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ library->mappings_count = 0; library->mappings_size = INIT_MAPPINGS;
+ pm_memusage_zero(&library->total_usage);
+
+ libraries[libraries_count++] = library;
+
+ return library;
+}
+
+struct mapping_info *get_mapping(struct library_info *library, struct process_info *proc) {
+ struct mapping_info *mapping;
+ int i;
+
+ for (i = 0; i < library->mappings_count; i++) {
+ if (library->mappings[i]->proc == proc)
+ return library->mappings[i];
+ }
+
+ if (library->mappings_count >= library->mappings_size) {
+ library->mappings = realloc(library->mappings,
+ 2 * library->mappings_size * sizeof(struct mapping*));
+ if (!library->mappings) {
+ fprintf(stderr, "Couldn't resize mappings array: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ library->mappings_size = 2 * library->mappings_size;
+ }
+
+ mapping = calloc(1, sizeof(*mapping));
+ if (!mapping) {
+ fprintf(stderr, "Couldn't allocate space for mapping struct: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ mapping->proc = proc;
+ pm_memusage_zero(&mapping->usage);
+
+ library->mappings[library->mappings_count++] = mapping;
+
+ return mapping;
+}
+
+struct process_info *get_process(pid_t pid) {
+ struct process_info *process;
+
+ process = calloc(1, sizeof(*process));
+ if (!process) {
+ fprintf(stderr, "Couldn't allocate space for process struct: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ process->pid = pid;
+ getprocname(pid, process->cmdline, sizeof(process->cmdline));
+
+ return process;
+}
+
+int main(int argc, char *argv[]) {
+ char cmdline[256];
+ char *prefix;
+ size_t prefix_len;
+ int (*compfn)(const void *a, const void *b);
+
+ pm_kernel_t *ker;
+ pm_process_t *proc;
+
+ pid_t *pids;
+ size_t num_procs;
+
+ pm_map_t **maps;
+ size_t num_maps;
+ pm_memusage_t map_usage;
+
+ struct library_info *li, **lis;
+ struct mapping_info *mi, **mis;
+ struct process_info *pi;
+
+ int i, j, error;
+
+ compfn = &sort_by_pss;
+ order = -1;
+ prefix = NULL;
+ prefix_len = 0;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-P")) {
+ if (i + 1 >= argc) {
+ fprintf(stderr, "Option -P requires an argument.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ prefix = argv[++i];
+ prefix_len = strlen(prefix);
+ continue;
+ }
+ if (!strcmp(argv[i], "-v")) { compfn = &sort_by_vss; continue; }
+ if (!strcmp(argv[i], "-r")) { compfn = &sort_by_rss; continue; }
+ if (!strcmp(argv[i], "-p")) { compfn = &sort_by_pss; continue; }
+ if (!strcmp(argv[i], "-u")) { compfn = &sort_by_uss; continue; }
+ if (!strcmp(argv[i], "-R")) { order *= -1; continue; }
+ if (!strcmp(argv[i], "-h")) { usage(argv[0]); exit(0); }
+ fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ libraries = malloc(INIT_LIBRARIES * sizeof(struct library_info *));
+ libraries_count = 0; libraries_size = INIT_LIBRARIES;
+
+ error = pm_kernel_create(&ker);
+ if (error) {
+ fprintf(stderr, "Error initializing kernel interface -- "
+ "does this kernel have pagemap?\n");
+ exit(EXIT_FAILURE);
+ }
+
+ error = pm_kernel_pids(ker, &pids, &num_procs);
+ if (error) {
+ fprintf(stderr, "Error listing processes.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < num_procs; i++) {
+ error = pm_process_create(ker, pids[i], &proc);
+ if (error) {
+ fprintf(stderr, "warning: could not create process interface for %d\n", pids[i]);
+ continue;
+ }
+
+ pi = get_process(pids[i]);
+
+ error = pm_process_maps(proc, &maps, &num_maps);
+ if (error) {
+ fprintf(stderr, "Error listing maps for process %d.\n", proc->pid);
+ exit(EXIT_FAILURE);
+ }
+
+ for (j = 0; j < num_maps; j++) {
+ if (prefix && (strncmp(pm_map_name(maps[j]), prefix, prefix_len)))
+ continue;
+
+ li = get_library(pm_map_name(maps[j]));
+ if (!li)
+ continue;
+
+ mi = get_mapping(li, pi);
+
+ error = pm_map_usage(maps[j], &map_usage);
+ if (error) {
+ fprintf(stderr, "Error getting map memory usage of "
+ "map %s in process %d.\n",
+ pm_map_name(maps[j]), proc->pid);
+ exit(EXIT_FAILURE);
+ }
+ pm_memusage_add(&mi->usage, &map_usage);
+ pm_memusage_add(&li->total_usage, &map_usage);
+ }
+ }
+
+ printf( " %6s %6s %6s %6s %6s %s\n", "RSStot", "VSS", "RSS", "PSS", "USS", "Name/PID");
+ fflush(stdout);
+
+ qsort(libraries, libraries_count, sizeof(libraries[0]), &licmp);
+
+ for (i = 0; i < libraries_count; i++) {
+ li = libraries[i];
+
+ printf("%6dK %6s %6s %6s %6s %s\n", li->total_usage.pss / 1024, "", "", "", "", li->name);
+ fflush(stdout);
+
+ qsort(li->mappings, li->mappings_count, sizeof(li->mappings[0]), compfn);
+
+ for (j = 0; j < li->mappings_count; j++) {
+ mi = li->mappings[j];
+ pi = mi->proc;
+ printf( " %6s %6dK %6dK %6dK %6dK %s [%d]\n", "",
+ mi->usage.vss / 1024,
+ mi->usage.rss / 1024,
+ mi->usage.pss / 1024,
+ mi->usage.uss / 1024,
+ pi->cmdline,
+ pi->pid);
+ }
+ printf("\n");
+ fflush(stdout);
+ }
+
+ return 0;
+}
+
+static void usage(char *myname) {
+ fprintf(stderr, "Usage: %s [ -P | -L ] [ -v | -r | -p | -u | -h ]\n"
+ "\n"
+ "Sort options:\n"
+ " -v Sort processes by VSS.\n"
+ " -r Sort processes by RSS.\n"
+ " -p Sort processes by PSS.\n"
+ " -u Sort processes by USS.\n"
+ " (Default sort order is PSS.)\n"
+ " -P /path Limit libraries displayed to those in path.\n"
+ " -R Reverse sort order (default is descending).\n"
+ " -h Display this help screen.\n",
+ myname);
+}
+
+static int getprocname(pid_t pid, char *buf, size_t len) {
+ char filename[20];
+ FILE *f;
+
+ sprintf(filename, "/proc/%d/cmdline", pid);
+ f = fopen(filename, "r");
+ if (!f) { *buf = '\0'; return 1; }
+ if (!fgets(buf, len, f)) { *buf = '\0'; return 2; }
+ fclose(f);
+ return 0;
+}
+
+static int numcmp(long long a, long long b) {
+ if (a < b) return -1;
+ if (a > b) return 1;
+ return 0;
+}
+
+static int licmp(const void *a, const void *b) {
+ return order * numcmp(
+ (*((struct library_info**)a))->total_usage.pss,
+ (*((struct library_info**)b))->total_usage.pss
+ );
+}
+
+#define create_sort(field, compfn) \
+ static int sort_by_ ## field (const void *a, const void *b) { \
+ return order * compfn( \
+ (*((struct mapping_info**)a))->usage.field, \
+ (*((struct mapping_info**)b))->usage.field \
+ ); \
+ }
+
+create_sort(vss, numcmp)
+create_sort(rss, numcmp)
+create_sort(pss, numcmp)
+create_sort(uss, numcmp)
diff --git a/procmem/Android.mk b/procmem/Android.mk
new file mode 100644
index 00000000..ffd56604
--- /dev/null
+++ b/procmem/Android.mk
@@ -0,0 +1,30 @@
+# 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_SRC_FILES := procmem.c
+
+LOCAL_C_INCLUDES := $(call include-path-for, libpagemap)
+
+LOCAL_SHARED_LIBRARIES := libpagemap
+
+LOCAL_MODULE := procmem
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+
+LOCAL_MODULE_TAGS := debug
+
+include $(BUILD_EXECUTABLE)
diff --git a/procmem/MODULE_LICENSE_APACHE2 b/procmem/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/procmem/MODULE_LICENSE_APACHE2
diff --git a/procmem/NOTICE b/procmem/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/procmem/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/procmem/procmem.c b/procmem/procmem.c
new file mode 100644
index 00000000..03c9f51f
--- /dev/null
+++ b/procmem/procmem.c
@@ -0,0 +1,322 @@
+/*
+ * 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 <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <pagemap/pagemap.h>
+
+/* Information about a single mapping */
+struct map_info {
+ pm_map_t *map;
+ pm_memusage_t usage;
+ /* page counts */
+ unsigned long shared_clean;
+ unsigned long shared_dirty;
+ unsigned long private_clean;
+ unsigned long private_dirty;
+};
+
+/* display the help screen */
+static void usage(const char *cmd);
+
+/* qsort compare function to compare maps by PSS */
+int comp_pss(const void *a, const void *b);
+
+int main(int argc, char *argv[]) {
+ pid_t pid;
+
+ /* libpagemap context */
+ pm_kernel_t *ker;
+ int pagesize; /* cached for speed */
+ pm_process_t *proc;
+
+ /* maps and such */
+ pm_map_t **maps; int num_maps;
+
+ struct map_info **mis;
+ struct map_info *mi;
+
+ /* pagemap information */
+ uint64_t *pagemap; int num_pages;
+ unsigned long address; uint64_t mapentry;
+ uint64_t count, flags;
+
+ /* totals */
+ unsigned long total_shared_clean, total_shared_dirty, total_private_clean, total_private_dirty;
+ pm_memusage_t total_usage;
+
+ /* command-line options */
+ int ws;
+#define WS_OFF (0)
+#define WS_ONLY (1)
+#define WS_RESET (2)
+ int (*compfn)(const void *a, const void *b);
+ int hide_zeros;
+
+ /* temporary variables */
+ int i, j;
+ char *endptr;
+ int error;
+
+ if (argc < 2) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ ws = WS_OFF;
+ compfn = NULL;
+ hide_zeros = 0;
+ for (i = 1; i < argc - 1; i++) {
+ if (!strcmp(argv[i], "-w")) { ws = WS_ONLY; continue; }
+ if (!strcmp(argv[i], "-W")) { ws = WS_RESET; continue; }
+ if (!strcmp(argv[i], "-m")) { compfn = NULL; continue; }
+ if (!strcmp(argv[i], "-p")) { compfn = &comp_pss; continue; }
+ if (!strcmp(argv[i], "-h")) { hide_zeros = 1; continue; }
+ fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ pid = (pid_t)strtol(argv[argc - 1], &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Invalid PID \"%s\".\n", argv[argc - 1]);
+ exit(EXIT_FAILURE);
+ }
+
+ error = pm_kernel_create(&ker);
+ if (error) {
+ fprintf(stderr, "error creating kernel interface -- "
+ "does this kernel have pagemap?\n");
+ exit(EXIT_FAILURE);
+ }
+
+ pagesize = pm_kernel_pagesize(ker);
+
+ error = pm_process_create(ker, pid, &proc);
+ if (error) {
+ fprintf(stderr, "error creating process interface -- "
+ "does process %d really exist?\n", pid);
+ exit(EXIT_FAILURE);
+ }
+
+ if (ws == WS_RESET) {
+ error = pm_process_workingset(proc, NULL, 1);
+ if (error) {
+ fprintf(stderr, "error resetting working set for process.\n");
+ exit(EXIT_FAILURE);
+ }
+ exit(EXIT_SUCCESS);
+ }
+
+ /* get maps, and allocate our map_info array */
+ error = pm_process_maps(proc, &maps, &num_maps);
+ if (error) {
+ fprintf(stderr, "error listing maps.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ mis = (struct map_info **)calloc(num_maps, sizeof(struct map_info *));
+ if (!mis) {
+ fprintf(stderr, "error allocating map_info array: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /* print header */
+ if (ws == WS_ONLY) {
+ printf("%7s %7s %7s %7s %7s %7s %7s %s\n",
+ "WRss", "WPss", "WUss", "WShCl", "WShDi", "WPrCl", "WPrDi", "Name");
+ printf("%7s %7s %7s %7s %7s %7s %7s %s\n",
+ "-------", "-------", "-------", "-------", "-------", "-------", "-------", "");
+ } else {
+ printf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n",
+ "Vss", "Rss", "Pss", "Uss", "ShCl", "ShDi", "PrCl", "PrDi", "Name");
+ printf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n",
+ "-------", "-------", "-------", "-------", "-------", "-------", "-------", "-------", "");
+ }
+
+ /* zero things */
+ pm_memusage_zero(&total_usage);
+ total_shared_clean = total_shared_dirty = total_private_clean = total_private_dirty = 0;
+
+ for (i = 0; i < num_maps; i++) {
+ mi = (struct map_info *)calloc(1, sizeof(struct map_info));
+ if (!mi) {
+ fprintf(stderr, "error allocating map_info: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ mi->map = maps[i];
+
+ /* get, and sum, memory usage */
+
+ if (ws == WS_ONLY)
+ error = pm_map_workingset(mi->map, &mi->usage);
+ else
+ error = pm_map_usage(mi->map, &mi->usage);
+ if (error) {
+ fflush(stdout);
+ fprintf(stderr, "error getting usage for map.\n");
+ continue;
+ }
+
+ pm_memusage_add(&total_usage, &mi->usage);
+
+ /* get, and sum, individual page counts */
+
+ error = pm_map_pagemap(mi->map, &pagemap, &num_pages);
+ if (error) {
+ fflush(stdout);
+ fprintf(stderr, "error getting pagemap for map.\n");
+ continue;
+ }
+
+ mi->shared_clean = mi->shared_dirty = mi->private_clean = mi->private_dirty = 0;
+
+ for (j = 0; j < num_pages; j++) {
+ address = pm_map_start(mi->map) + j * ker->pagesize;
+ mapentry = pagemap[j];
+
+ if (PM_PAGEMAP_PRESENT(mapentry) && !PM_PAGEMAP_SWAPPED(mapentry)) {
+
+ error = pm_kernel_count(ker, PM_PAGEMAP_PFN(mapentry), &count);
+ if (error) {
+ fflush(stdout);
+ fprintf(stderr, "error getting count for frame.\n");
+ }
+
+ error = pm_kernel_flags(ker, PM_PAGEMAP_PFN(mapentry), &flags);
+ if (error) {
+ fflush(stdout);
+ fprintf(stderr, "error getting flags for frame.\n");
+ }
+
+ if ((ws != WS_ONLY) || (flags & PM_PAGE_REFERENCED)) {
+ if (count > 1) {
+ if (flags & PM_PAGE_DIRTY)
+ mi->shared_dirty++;
+ else
+ mi->shared_clean++;
+ } else {
+ if (flags & PM_PAGE_DIRTY)
+ mi->private_dirty++;
+ else
+ mi->private_clean++;
+ }
+ }
+ }
+ }
+
+ total_shared_clean += mi->shared_clean;
+ total_shared_dirty += mi->shared_dirty;
+ total_private_clean += mi->private_clean;
+ total_private_dirty += mi->private_dirty;
+
+ /* add to array */
+ mis[i] = mi;
+ }
+
+ /* sort the array, if requested (compfn == NULL for original order) */
+ if (compfn)
+ qsort(mis, num_maps, sizeof(mis[0]), compfn);
+
+ for (i = 0; i < num_maps; i++) {
+ mi = mis[i];
+
+ if (hide_zeros && !mi->usage.rss)
+ continue;
+
+ if (ws == WS_ONLY) {
+ printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n",
+ (long)mi->usage.rss / 1024,
+ (long)mi->usage.pss / 1024,
+ (long)mi->usage.uss / 1024,
+ mi->shared_clean * pagesize / 1024,
+ mi->shared_dirty * pagesize / 1024,
+ mi->private_clean * pagesize / 1024,
+ mi->private_dirty * pagesize / 1024,
+ pm_map_name(mi->map)
+ );
+ } else {
+ printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n",
+ (long)mi->usage.vss / 1024,
+ (long)mi->usage.rss / 1024,
+ (long)mi->usage.pss / 1024,
+ (long)mi->usage.uss / 1024,
+ mi->shared_clean * pagesize / 1024,
+ mi->shared_dirty * pagesize / 1024,
+ mi->private_clean * pagesize / 1024,
+ mi->private_dirty * pagesize / 1024,
+ pm_map_name(mi->map)
+ );
+ }
+ }
+
+ /* print totals */
+ if (ws == WS_ONLY) {
+ printf("%7s %7s %7s %7s %7s %7s %7s %s\n",
+ "-------", "-------", "-------", "-------", "-------", "-------", "-------", "");
+ printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n",
+ (long)total_usage.rss / 1024,
+ (long)total_usage.pss / 1024,
+ (long)total_usage.uss / 1024,
+ total_shared_clean * pagesize / 1024,
+ total_shared_dirty * pagesize / 1024,
+ total_private_clean * pagesize / 1024,
+ total_private_dirty * pagesize / 1024,
+ "TOTAL"
+ );
+ } else {
+ printf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n",
+ "-------", "-------", "-------", "-------", "-------", "-------", "-------", "-------", "");
+ printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n",
+ (long)total_usage.vss / 1024,
+ (long)total_usage.rss / 1024,
+ (long)total_usage.pss / 1024,
+ (long)total_usage.uss / 1024,
+ total_shared_clean * pagesize / 1024,
+ total_shared_dirty * pagesize / 1024,
+ total_private_clean * pagesize / 1024,
+ total_private_dirty * pagesize / 1024,
+ "TOTAL"
+ );
+ }
+
+ return 0;
+}
+
+static void usage(const char *cmd) {
+ fprintf(stderr, "Usage: %s [ -w | -W ] [ -p | -m ] [ -h ] pid\n"
+ " -w Displays statistics for the working set only.\n"
+ " -W Resets the working set of the process.\n"
+ " -p Sort by PSS.\n"
+ " -m Sort by mapping order (as read from /proc).\n"
+ " -h Hide maps with no RSS.\n",
+ cmd);
+}
+
+int comp_pss(const void *a, const void *b) {
+ struct map_info *ma, *mb;
+
+ ma = *((struct map_info **)a);
+ mb = *((struct map_info **)b);
+
+ if (mb->usage.pss < ma->usage.pss) return -1;
+ if (mb->usage.pss > ma->usage.pss) return 1;
+ return 0;
+}
diff --git a/procrank/Android.mk b/procrank/Android.mk
new file mode 100644
index 00000000..eb487105
--- /dev/null
+++ b/procrank/Android.mk
@@ -0,0 +1,30 @@
+# 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_SRC_FILES := procrank.c
+
+LOCAL_C_INCLUDES := $(call include-path-for, libpagemap)
+
+LOCAL_SHARED_LIBRARIES := libpagemap
+
+LOCAL_MODULE := procrank
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+
+LOCAL_MODULE_TAGS := debug
+
+include $(BUILD_EXECUTABLE)
diff --git a/procrank/MODULE_LICENSE_APACHE2 b/procrank/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/procrank/MODULE_LICENSE_APACHE2
diff --git a/procrank/NOTICE b/procrank/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/procrank/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/procrank/procrank.c b/procrank/procrank.c
new file mode 100644
index 00000000..585fddcd
--- /dev/null
+++ b/procrank/procrank.c
@@ -0,0 +1,206 @@
+/*
+ * 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 <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <pagemap/pagemap.h>
+
+struct proc_info {
+ pid_t pid;
+ pm_memusage_t usage;
+ unsigned long wss;
+};
+
+static void usage(char *myname);
+static int getprocname(pid_t pid, char *buf, size_t len);
+static int numcmp(long long a, long long b);
+
+#define declare_sort(field) \
+ static int sort_by_ ## field (const void *a, const void *b)
+
+declare_sort(vss);
+declare_sort(rss);
+declare_sort(pss);
+declare_sort(uss);
+
+int (*compfn)(const void *a, const void *b);
+static int order;
+
+#define MAX_PROCS 256
+
+int main(int argc, char *argv[]) {
+ pm_kernel_t *ker;
+ pm_process_t *proc;
+ pid_t *pids;
+ struct proc_info *procs[MAX_PROCS];
+ size_t num_procs;
+ char cmdline[256];
+ int error;
+
+ #define WS_OFF 0
+ #define WS_ONLY 1
+ #define WS_RESET 2
+ int ws;
+
+ int i, j;
+
+ compfn = &sort_by_pss;
+ order = -1;
+ ws = WS_OFF;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-v")) { compfn = &sort_by_vss; continue; }
+ if (!strcmp(argv[i], "-r")) { compfn = &sort_by_rss; continue; }
+ if (!strcmp(argv[i], "-p")) { compfn = &sort_by_pss; continue; }
+ if (!strcmp(argv[i], "-u")) { compfn = &sort_by_uss; continue; }
+ if (!strcmp(argv[i], "-w")) { ws = WS_ONLY; continue; }
+ if (!strcmp(argv[i], "-W")) { ws = WS_RESET; continue; }
+ if (!strcmp(argv[i], "-R")) { order *= -1; continue; }
+ if (!strcmp(argv[i], "-h")) { usage(argv[0]); exit(0); }
+ fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ error = pm_kernel_create(&ker);
+ if (error) {
+ fprintf(stderr, "Error creating kernel interface -- "
+ "does this kernel have pagemap?\n");
+ exit(EXIT_FAILURE);
+ }
+
+ error = pm_kernel_pids(ker, &pids, &num_procs);
+ if (error) {
+ fprintf(stderr, "Error listing processes.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < num_procs; i++) {
+ procs[i] = malloc(sizeof(struct proc_info));
+ if (!procs[i]) {
+ fprintf(stderr, "malloc: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ procs[i]->pid = pids[i];
+ error = pm_process_create(ker, pids[i], &proc);
+ if (!error) {
+ switch (ws) {
+ case WS_OFF:
+ pm_process_usage(proc, &procs[i]->usage);
+ break;
+ case WS_ONLY:
+ pm_process_workingset(proc, &procs[i]->usage, 0);
+ break;
+ case WS_RESET:
+ pm_process_workingset(proc, NULL, 1);
+ break;
+ }
+ pm_process_destroy(proc);
+ } else {
+ fprintf(stderr, "warning: could not create process interface for %d\n", pids[i]);
+ pm_memusage_zero(&procs[i]->usage);
+ }
+ }
+
+ free(pids);
+
+ if (ws == WS_RESET) exit(0);
+
+ j = 0;
+ for (i = 0; i < num_procs; i++) {
+ if (procs[i]->usage.vss)
+ procs[j++] = procs[i];
+ }
+ num_procs = j;
+
+ qsort(procs, num_procs, sizeof(procs[0]), compfn);
+
+ if (ws)
+ printf("%5s %7s %7s %7s %s\n", "PID", "WRss", "WPss", "WUss", "cmdline");
+ else
+ printf("%5s %7s %7s %7s %7s %s\n", "PID", "Vss", "Rss", "Pss", "Uss", "cmdline");
+ for (i = 0; i < num_procs; i++) {
+ getprocname(procs[i]->pid, cmdline, sizeof(cmdline));
+ if (ws)
+ printf("%5d %6dK %6dK %6dK %s\n",
+ procs[i]->pid,
+ procs[i]->usage.rss / 1024,
+ procs[i]->usage.pss / 1024,
+ procs[i]->usage.uss / 1024,
+ cmdline
+ );
+ else
+ printf("%5d %6dK %6dK %6dK %6dK %s\n",
+ procs[i]->pid,
+ procs[i]->usage.vss / 1024,
+ procs[i]->usage.rss / 1024,
+ procs[i]->usage.pss / 1024,
+ procs[i]->usage.uss / 1024,
+ cmdline
+ );
+ }
+
+ return 0;
+}
+
+static void usage(char *myname) {
+ fprintf(stderr, "Usage: %s [ -W ] [ -v | -r | -p | -u | -h ]\n"
+ " -v Sort by VSS.\n"
+ " -r Sort by RSS.\n"
+ " -p Sort by PSS.\n"
+ " -u Sort by USS.\n"
+ " (Default sort order is PSS.)\n"
+ " -R Reverse sort order (default is descending).\n"
+ " -w Display statistics for working set only.\n"
+ " -W Reset working set of all processes.\n"
+ " -h Display this help screen.\n",
+ myname);
+}
+
+static int getprocname(pid_t pid, char *buf, size_t len) {
+ char filename[20];
+ FILE *f;
+
+ sprintf(filename, "/proc/%d/cmdline", pid);
+ f = fopen(filename, "r");
+ if (!f) { *buf = '\0'; return 1; }
+ if (!fgets(buf, len, f)) { *buf = '\0'; return 2; }
+ fclose(f);
+ return 0;
+}
+
+static int numcmp(long long a, long long b) {
+ if (a < b) return -1;
+ if (a > b) return 1;
+ return 0;
+}
+
+#define create_sort(field, compfn) \
+ static int sort_by_ ## field (const void *a, const void *b) { \
+ return order * compfn( \
+ (*((struct proc_info**)a))->usage.field, \
+ (*((struct proc_info**)b))->usage.field \
+ ); \
+ }
+
+create_sort(vss, numcmp)
+create_sort(rss, numcmp)
+create_sort(pss, numcmp)
+create_sort(uss, numcmp)
diff --git a/showmap/Android.mk b/showmap/Android.mk
new file mode 100644
index 00000000..5c90f12f
--- /dev/null
+++ b/showmap/Android.mk
@@ -0,0 +1,13 @@
+# Copyright 2006 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= showmap.c
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE:= showmap
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/showmap/MODULE_LICENSE_APACHE2 b/showmap/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/showmap/MODULE_LICENSE_APACHE2
diff --git a/showmap/NOTICE b/showmap/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/showmap/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/showmap/showmap.c b/showmap/showmap.c
new file mode 100644
index 00000000..4abd56a8
--- /dev/null
+++ b/showmap/showmap.c
@@ -0,0 +1,234 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <ctype.h>
+#include <stddef.h>
+
+typedef struct mapinfo mapinfo;
+
+struct mapinfo {
+ mapinfo *next;
+ unsigned start;
+ unsigned end;
+ unsigned size;
+ unsigned rss;
+ unsigned pss;
+ unsigned shared_clean;
+ unsigned shared_dirty;
+ unsigned private_clean;
+ unsigned private_dirty;
+ char name[1];
+};
+
+// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /android/lib/libcomposer.so
+// 012345678901234567890123456789012345678901234567890123456789
+// 0 1 2 3 4 5
+
+mapinfo *read_mapinfo(FILE *fp)
+{
+ char line[1024];
+ mapinfo *mi;
+ int len;
+ int skip;
+
+again:
+ skip = 0;
+
+ if(fgets(line, 1024, fp) == 0) return 0;
+
+ len = strlen(line);
+ if(len < 1) return 0;
+ line[--len] = 0;
+
+ mi = calloc(1, sizeof(mapinfo) + len + 16);
+ if(mi == 0) return 0;
+
+ mi->start = strtoul(line, 0, 16);
+ mi->end = strtoul(line + 9, 0, 16);
+
+ if(len < 50) {
+ if((mi->start >= 0x10000000) && (mi->start < 0x40000000)) {
+ strcpy(mi->name, "[stack]");
+ } else if(mi->start > 0x50000000) {
+ strcpy(mi->name, "[lib_bss]");
+ } else {
+ strcpy(mi->name, "[anon]");
+ }
+ } else {
+ strcpy(mi->name, line + 49);
+ }
+
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Size: %d kB", &mi->size) != 1) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Rss: %d kB", &mi->rss) != 1) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Pss: %d kB", &mi->pss) == 1)
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Shared_Clean: %d kB", &mi->shared_clean) != 1) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Shared_Dirty: %d kB", &mi->shared_dirty) != 1) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Private_Clean: %d kB", &mi->private_clean) != 1) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Private_Dirty: %d kB", &mi->private_dirty) != 1) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+
+ if(skip) {
+ free(mi);
+ goto again;
+ }
+
+ return mi;
+oops:
+ fprintf(stderr, "WARNING: Format of /proc/<pid>/smaps has changed!\n");
+ free(mi);
+ return 0;
+}
+
+
+mapinfo *load_maps(int pid, int verbose)
+{
+ char tmp[128];
+ FILE *fp;
+ mapinfo *milist = 0;
+ mapinfo *mi;
+
+ sprintf(tmp, "/proc/%d/smaps", pid);
+ fp = fopen(tmp, "r");
+ if(fp == 0) return 0;
+
+ while((mi = read_mapinfo(fp)) != 0) {
+ /* if not verbose, coalesce mappings from the same entity */
+ if(!verbose && milist) {
+ if((!strcmp(mi->name, milist->name) && (mi->name[0] != '['))
+ || !strcmp(mi->name,"[lib_bss]")) {
+ milist->size += mi->size;
+ milist->rss += mi->rss;
+ milist->pss += mi->pss;
+ milist->shared_clean += mi->shared_clean;
+ milist->shared_dirty += mi->shared_dirty;
+ milist->private_clean += mi->private_clean;
+ milist->private_dirty += mi->private_dirty;
+ milist->end = mi->end;
+ free(mi);
+ continue;
+ }
+ }
+
+ mi->next = milist;
+ milist = mi;
+ }
+ fclose(fp);
+
+ return milist;
+}
+
+static int verbose = 0;
+static int terse = 0;
+static int addresses = 0;
+
+int show_map(int pid)
+{
+ mapinfo *milist;
+ mapinfo *mi;
+ unsigned shared_dirty = 0;
+ unsigned shared_clean = 0;
+ unsigned private_dirty = 0;
+ unsigned private_clean = 0;
+ unsigned rss = 0;
+ unsigned pss = 0;
+ unsigned size = 0;
+
+ milist = load_maps(pid, verbose);
+ if(milist == 0) {
+ fprintf(stderr,"cannot get /proc/smaps for pid %d\n", pid);
+ return 1;
+ }
+
+ if(addresses) {
+ printf("start end shared private object\n");
+ printf("-------- -------- -------- -------- ------------------------------\n");
+ } else {
+ printf("virtual shared shared private private\n");
+ printf("size RSS PSS clean dirty clean dirty object\n");
+ printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n");
+ }
+ for(mi = milist; mi; mi = mi->next){
+ shared_clean += mi->shared_clean;
+ shared_dirty += mi->shared_dirty;
+ private_clean += mi->private_clean;
+ private_dirty += mi->private_dirty;
+ rss += mi->rss;
+ pss += mi->pss;
+ size += mi->size;
+
+ if(terse && !mi->private_dirty) continue;
+
+ if(addresses) {
+ printf("%08x %08x %8d %8d %s\n", mi->start, mi->end,
+ mi->shared_clean + mi->shared_dirty,
+ mi->private_clean + mi->private_dirty,
+ mi->name);
+ } else {
+ printf("%8d %8d %8d %8d %8d %8d %8d %s\n", mi->size,
+ mi->rss,
+ mi->pss,
+ mi->shared_clean, mi->shared_dirty,
+ mi->private_clean, mi->private_dirty,
+ mi->name);
+ }
+ }
+ if(addresses) {
+ printf("-------- -------- -------- -------- ------------------------------\n");
+ printf(" %8d %8d TOTAL\n",
+ shared_dirty + shared_clean,
+ private_dirty + private_clean);
+ } else {
+ printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n");
+ printf("%8d %8d %8d %8d %8d %8d %8d TOTAL\n", size,
+ rss, pss,
+ shared_clean, shared_dirty,
+ private_clean, private_dirty);
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int usage = 1;
+
+ for(argc--, argv++; argc > 0; argc--, argv++) {
+ if(!strcmp(argv[0],"-v")) {
+ verbose = 1;
+ continue;
+ }
+ if(!strcmp(argv[0],"-t")) {
+ terse = 1;
+ continue;
+ }
+ if(!strcmp(argv[0],"-a")) {
+ addresses = 1;
+ continue;
+ }
+ show_map(atoi(argv[0]));
+ usage = 0;
+ }
+
+ if(usage) {
+ fprintf(stderr,
+ "showmap [-t] [-v] [-c] <pid>\n"
+ " -t = terse (show only items with private pages)\n"
+ " -v = verbose (don't coalesce adjacant maps)\n"
+ " -a = addresses (show virtual memory map)\n"
+ );
+ }
+
+ return 0;
+}
diff --git a/showslab/Android.mk b/showslab/Android.mk
new file mode 100644
index 00000000..c914a8b6
--- /dev/null
+++ b/showslab/Android.mk
@@ -0,0 +1,15 @@
+# Copyright 2007 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= showslab.c
+LOCAL_SHARED_LIBRARIES :=
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE:= showslab
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/showslab/MODULE_LICENSE_APACHE2 b/showslab/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/showslab/MODULE_LICENSE_APACHE2
diff --git a/showslab/NOTICE b/showslab/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/showslab/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/showslab/showslab.c b/showslab/showslab.c
new file mode 100644
index 00000000..9c9e60eb
--- /dev/null
+++ b/showslab/showslab.c
@@ -0,0 +1,351 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+
+#define STRINGIFY_ARG(a) #a
+#define STRINGIFY(a) STRINGIFY_ARG(a)
+
+#define DEF_SORT_FUNC sort_nr_objs
+#define SLABINFO_LINE_LEN 512 /* size of longest line */
+#define SLABINFO_NAME_LEN 32 /* cache name size (will truncate) */
+#define SLABINFO_FILE "/proc/slabinfo"
+#define DEF_NR_ROWS 15 /* default nr of caches to show */
+
+/* object representing a slab cache (each line of slabinfo) */
+struct slab_info {
+ char name[SLABINFO_NAME_LEN]; /* name of this cache */
+ struct slab_info *next;
+ unsigned long nr_pages; /* size of cache in pages */
+ unsigned long nr_objs; /* number of objects in this cache */
+ unsigned long nr_active_objs; /* number of active objects */
+ unsigned long obj_size; /* size of each object */
+ unsigned long objs_per_slab; /* number of objects per slab */
+ unsigned long nr_slabs; /* number of slabs in this cache */
+ unsigned long use; /* percent full: total / active */
+};
+
+/* object representing system-wide statistics */
+struct slab_stat {
+ unsigned long total_size; /* size of all objects */
+ unsigned long active_size; /* size of all active objects */
+ unsigned long nr_objs; /* total number of objects */
+ unsigned long nr_active_objs; /* total number of active objects */
+ unsigned long nr_slabs; /* total number of slabs */
+ unsigned long nr_active_slabs; /* total number of active slabs*/
+ unsigned long nr_caches; /* number of caches */
+ unsigned long nr_active_caches; /* number of active caches */
+ unsigned long avg_obj_size; /* average object size */
+ unsigned long min_obj_size; /* size of smallest object */
+ unsigned long max_obj_size; /* size of largest object */
+};
+
+typedef int (*sort_t)(const struct slab_info *, const struct slab_info *);
+static sort_t sort_func;
+
+/*
+ * get_slabinfo - open, read, and parse a slabinfo 2.x file, which has the
+ * following format:
+ *
+ * slabinfo - version: 2.1
+ * <name> <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab>
+ * : tunables <limit> <batchcount> <sharedfactor>
+ * : slabdata <active_slabs> <num_slabs> <sharedavail>
+ *
+ * Returns the head of the new list of slab_info structures, or NULL on error.
+ */
+static struct slab_info * get_slabinfo(struct slab_stat *stats)
+{
+ struct slab_info *head = NULL, *p = NULL, *prev = NULL;
+ FILE *slabfile;
+ char line[SLABINFO_LINE_LEN];
+ unsigned int major, minor;
+
+ slabfile = fopen(SLABINFO_FILE, "r");
+ if (!slabfile) {
+ perror("fopen");
+ return NULL;
+ }
+
+ if (!fgets(line, SLABINFO_LINE_LEN, slabfile)) {
+ fprintf(stderr, "cannot read from " SLABINFO_FILE "\n");
+ return NULL;
+ }
+
+ if (sscanf(line, "slabinfo - version: %u.%u", &major, &minor) != 2) {
+ fprintf(stderr, "unable to parse slabinfo version!\n");
+ return NULL;
+ }
+
+ if (major != 2 || minor > 1) {
+ fprintf(stderr, "we only support slabinfo 2.0 and 2.1!\n");
+ return NULL;
+ }
+
+ stats->min_obj_size = INT_MAX;
+
+ while (fgets(line, SLABINFO_LINE_LEN, slabfile)) {
+ unsigned long nr_active_slabs, pages_per_slab;
+ int ret;
+
+ if (line[0] == '#')
+ continue;
+
+ p = malloc(sizeof (struct slab_info));
+ if (!p) {
+ perror("malloc");
+ head = NULL;
+ break;
+ }
+ if (stats->nr_caches++ == 0)
+ head = prev = p;
+
+ ret = sscanf(line, "%" STRINGIFY(SLABINFO_NAME_LEN) "s"
+ " %lu %lu %lu %lu %lu : tunables %*d %*d %*d : \
+ slabdata %lu %lu %*d", p->name,
+ &p->nr_active_objs, &p->nr_objs,
+ &p->obj_size, &p->objs_per_slab,
+ &pages_per_slab,
+ &nr_active_slabs,
+ &p->nr_slabs);
+
+ if (ret != 8) {
+ fprintf(stderr, "unrecognizable data in slabinfo!\n");
+ head = NULL;
+ break;
+ }
+
+ if (p->obj_size < stats->min_obj_size)
+ stats->min_obj_size = p->obj_size;
+ if (p->obj_size > stats->max_obj_size)
+ stats->max_obj_size = p->obj_size;
+
+ p->nr_pages = p->nr_slabs * pages_per_slab;
+
+ if (p->nr_objs) {
+ p->use = 100 * p->nr_active_objs / p->nr_objs;
+ stats->nr_active_caches++;
+ } else
+ p->use = 0;
+
+ stats->nr_objs += p->nr_objs;
+ stats->nr_active_objs += p->nr_active_objs;
+ stats->total_size += p->nr_objs * p->obj_size;
+ stats->active_size += p->nr_active_objs * p->obj_size;
+ stats->nr_slabs += p->nr_slabs;
+ stats->nr_active_slabs += nr_active_slabs;
+
+ prev->next = p;
+ prev = p;
+ }
+
+ if (fclose(slabfile))
+ perror("fclose");
+
+ if (p)
+ p->next = NULL;
+ if (stats->nr_objs)
+ stats->avg_obj_size = stats->total_size / stats->nr_objs;
+
+ return head;
+}
+
+/*
+ * free_slablist - deallocate the memory associated with each node in the
+ * provided slab_info linked list
+ */
+static void free_slablist(struct slab_info *list)
+{
+ while (list) {
+ struct slab_info *temp = list->next;
+ free(list);
+ list = temp;
+ }
+}
+
+static struct slab_info *merge_objs(struct slab_info *a, struct slab_info *b)
+{
+ struct slab_info list;
+ struct slab_info *p = &list;
+
+ while (a && b) {
+ if (sort_func(a, b)) {
+ p->next = a;
+ p = a;
+ a = a->next;
+ } else {
+ p->next = b;
+ p = b;
+ b = b->next;
+ }
+ }
+
+ p->next = (a == NULL) ? b : a;
+ return list.next;
+}
+
+/*
+ * slabsort - merge sort the slab_info linked list based on sort_func
+ */
+static struct slab_info *slabsort(struct slab_info *list)
+{
+ struct slab_info *a, *b;
+
+ if (!list || !list->next)
+ return list;
+
+ a = list;
+ b = list->next;
+
+ while (b && b->next) {
+ list = list->next;
+ b = b->next->next;
+ }
+
+ b = list->next;
+ list->next = NULL;
+
+ return merge_objs(slabsort(a), slabsort(b));
+}
+
+/*
+ * Sort Routines. Each of these should be associated with a command-line
+ * search option. The functions should fit the prototype:
+ *
+ * int sort_foo(const struct slab_info *a, const struct slab_info *b)
+ *
+ * They return zero if the first parameter is smaller than the second.
+ * Otherwise, they return nonzero.
+ */
+
+static int sort_name(const struct slab_info *a, const struct slab_info *b)
+{
+ return (strcmp(a->name, b->name) < 0 ) ? 1: 0;
+}
+
+#define BUILD_SORT_FUNC(VAL) \
+ static int sort_ ## VAL \
+ (const struct slab_info *a, const struct slab_info *b) { \
+ return (a-> VAL > b-> VAL); }
+
+BUILD_SORT_FUNC(nr_objs)
+BUILD_SORT_FUNC(nr_active_objs)
+BUILD_SORT_FUNC(obj_size)
+BUILD_SORT_FUNC(objs_per_slab)
+BUILD_SORT_FUNC(nr_slabs)
+BUILD_SORT_FUNC(use)
+BUILD_SORT_FUNC(nr_pages)
+
+/*
+ * set_sort_func - return the slab_sort_func that matches the given key.
+ * On unrecognizable key, the call returns NULL.
+ */
+static void * set_sort_func(char key)
+{
+ switch (tolower(key)) {
+ case 'a':
+ return sort_nr_active_objs;
+ case 'c':
+ return sort_nr_pages;
+ case 'l':
+ return sort_nr_slabs;
+ case 'n':
+ return sort_name;
+ case 'o':
+ return sort_nr_objs;
+ case 'p':
+ return sort_objs_per_slab;
+ case 's':
+ return sort_obj_size;
+ case 'u':
+ return sort_use;
+ default:
+ return NULL;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ struct slab_info *list, *p;
+ struct slab_stat stats = { .nr_objs = 0 };
+ unsigned int page_size = getpagesize() / 1024, nr_rows = DEF_NR_ROWS, i;
+
+ sort_func = DEF_SORT_FUNC;
+
+ if (argc > 1) {
+ /* FIXME: Ugh. */
+ if (argc == 3 && !strcmp(argv[1], "-n")) {
+ errno = 0;
+ nr_rows = (unsigned int) strtoul(argv[2], NULL, 0);
+ if (errno) {
+ perror("strtoul");
+ exit(EXIT_FAILURE);
+ }
+ }
+ else if (argc == 3 && !strcmp(argv[1], "-s"))
+ sort_func = set_sort_func(argv[2][0]) ? : DEF_SORT_FUNC;
+ else {
+ fprintf(stderr, "usage: %s [options]\n\n", argv[0]);
+ fprintf(stderr, "options:\n");
+ fprintf(stderr, " -s S specify sort criteria S\n");
+ fprintf(stderr, " -h display this help\n\n");
+ fprintf(stderr, "Valid sort criteria:\n");
+ fprintf(stderr, " a: number of Active objects\n");
+ fprintf(stderr, " c: Cache size\n");
+ fprintf(stderr, " l: number of sLabs\n");
+ fprintf(stderr, " n: Name\n");
+ fprintf(stderr, " o: number of Objects\n");
+ fprintf(stderr, " p: objects Per slab\n");
+ fprintf(stderr, " s: object Size\n");
+ fprintf(stderr, " u: cache Utilization\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ list = get_slabinfo (&stats);
+ if (!list)
+ exit(EXIT_FAILURE);
+
+ printf(" Active / Total Objects (%% used) : %lu / %lu (%.1f%%)\n"
+ " Active / Total Slabs (%% used) : %lu / %lu (%.1f%%)\n"
+ " Active / Total Caches (%% used) : %lu / %lu (%.1f%%)\n"
+ " Active / Total Size (%% used) : %.2fK / %.2fK (%.1f%%)\n"
+ " Min / Avg / Max Object Size : %.2fK / %.2fK / %.2fK\n\n",
+ stats.nr_active_objs,
+ stats.nr_objs,
+ 100.0 * stats.nr_active_objs / stats.nr_objs,
+ stats.nr_active_slabs,
+ stats.nr_slabs,
+ 100.0 * stats.nr_active_slabs / stats.nr_slabs,
+ stats.nr_active_caches,
+ stats.nr_caches,
+ 100.0 * stats.nr_active_caches / stats.nr_caches,
+ stats.active_size / 1024.0,
+ stats.total_size / 1024.0,
+ 100.0 * stats.active_size / stats.total_size,
+ stats.min_obj_size / 1024.0,
+ stats.avg_obj_size / 1024.0,
+ stats.max_obj_size / 1024.0);
+
+ printf("%6s %6s %4s %8s %6s %8s %10s %-23s\n",
+ "OBJS", "ACTIVE", "USE", "OBJ SIZE", "SLABS",
+ "OBJ/SLAB", "CACHE SIZE", "NAME");
+
+ p = list = slabsort(list);
+ for (i = 0; i < nr_rows && p; i++) {
+ printf("%6lu %6lu %3lu%% %7.2fK %6lu %8lu %9luK %-23s\n",
+ p->nr_objs, p->nr_active_objs, p->use,
+ p->obj_size / 1024.0, p->nr_slabs,
+ p->objs_per_slab,
+ p->nr_pages * page_size,
+ p->name);
+ p = p->next;
+ }
+
+ free_slablist(list);
+
+ return 0;
+}
diff --git a/sound/Android.mk b/sound/Android.mk
new file mode 100644
index 00000000..7a58998b
--- /dev/null
+++ b/sound/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sound
+LOCAL_SRC_FILES := playwav.c
+LOCAL_MODULE_TAGS := tests
+include $(BUILD_EXECUTABLE)
+
diff --git a/sound/playwav.c b/sound/playwav.c
new file mode 100644
index 00000000..bb37d4a9
--- /dev/null
+++ b/sound/playwav.c
@@ -0,0 +1,377 @@
+/* Copyright (C) 2008 The Android Open Source Project
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <linux/ioctl.h>
+
+#define AUDIO_IOCTL_MAGIC 'a'
+
+#define AUDIO_START _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned)
+#define AUDIO_STOP _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned)
+#define AUDIO_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned)
+#define AUDIO_GET_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 3, unsigned)
+#define AUDIO_SET_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 4, unsigned)
+#define AUDIO_GET_STATS _IOR(AUDIO_IOCTL_MAGIC, 5, unsigned)
+
+struct msm_audio_config {
+ uint32_t buffer_size;
+ uint32_t buffer_count;
+ uint32_t channel_count;
+ uint32_t sample_rate;
+ uint32_t codec_type;
+ uint32_t unused[3];
+};
+
+struct msm_audio_stats {
+ uint32_t out_bytes;
+ uint32_t unused[3];
+};
+
+int pcm_play(unsigned rate, unsigned channels,
+ int (*fill)(void *buf, unsigned sz, void *cookie),
+ void *cookie)
+{
+ struct msm_audio_config config;
+ struct msm_audio_stats stats;
+ unsigned sz, n;
+ char buf[8192];
+ int afd;
+
+ afd = open("/dev/msm_pcm_out", O_RDWR);
+ if (afd < 0) {
+ perror("pcm_play: cannot open audio device");
+ return -1;
+ }
+
+ if(ioctl(afd, AUDIO_GET_CONFIG, &config)) {
+ perror("could not get config");
+ return -1;
+ }
+
+ config.channel_count = channels;
+ config.sample_rate = rate;
+ if (ioctl(afd, AUDIO_SET_CONFIG, &config)) {
+ perror("could not set config");
+ return -1;
+ }
+ sz = config.buffer_size;
+ if (sz > sizeof(buf)) {
+ fprintf(stderr,"too big\n");
+ return -1;
+ }
+
+ fprintf(stderr,"prefill\n");
+ for (n = 0; n < config.buffer_count; n++) {
+ if (fill(buf, sz, cookie))
+ break;
+ if (write(afd, buf, sz) != sz)
+ break;
+ }
+
+ fprintf(stderr,"start\n");
+ ioctl(afd, AUDIO_START, 0);
+
+ for (;;) {
+#if 0
+ if (ioctl(afd, AUDIO_GET_STATS, &stats) == 0)
+ fprintf(stderr,"%10d\n", stats.out_bytes);
+#endif
+ if (fill(buf, sz, cookie))
+ break;
+ if (write(afd, buf, sz) != sz)
+ break;
+ }
+
+done:
+ close(afd);
+ return 0;
+}
+
+/* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+
+static char *next;
+static unsigned avail;
+
+int fill_buffer(void *buf, unsigned sz, void *cookie)
+{
+ if (sz > avail)
+ return -1;
+ memcpy(buf, next, sz);
+ next += sz;
+ avail -= sz;
+ return 0;
+}
+
+void play_file(unsigned rate, unsigned channels,
+ int fd, unsigned count)
+{
+ next = malloc(count);
+ if (!next) {
+ fprintf(stderr,"could not allocate %d bytes\n", count);
+ return;
+ }
+ if (read(fd, next, count) != count) {
+ fprintf(stderr,"could not read %d bytes\n", count);
+ return;
+ }
+ avail = count;
+ pcm_play(rate, channels, fill_buffer, 0);
+}
+
+int wav_play(const char *fn)
+{
+ struct wav_header hdr;
+ unsigned rate, channels;
+ int fd;
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "playwav: cannot open '%s'\n", fn);
+ return -1;
+ }
+ if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ fprintf(stderr, "playwav: cannot read header\n");
+ return -1;
+ }
+ fprintf(stderr,"playwav: %d ch, %d hz, %d bit, %s\n",
+ hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
+ hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
+
+ if ((hdr.riff_id != ID_RIFF) ||
+ (hdr.riff_fmt != ID_WAVE) ||
+ (hdr.fmt_id != ID_FMT)) {
+ fprintf(stderr, "playwav: '%s' is not a riff/wave file\n", fn);
+ return -1;
+ }
+ if ((hdr.audio_format != FORMAT_PCM) ||
+ (hdr.fmt_sz != 16)) {
+ fprintf(stderr, "playwav: '%s' is not pcm format\n", fn);
+ return -1;
+ }
+ if (hdr.bits_per_sample != 16) {
+ fprintf(stderr, "playwav: '%s' is not 16bit per sample\n", fn);
+ return -1;
+ }
+
+ play_file(hdr.sample_rate, hdr.num_channels,
+ fd, hdr.data_sz);
+
+ return 0;
+}
+
+int wav_rec(const char *fn, unsigned channels, unsigned rate)
+{
+ struct wav_header hdr;
+ unsigned char buf[8192];
+ struct msm_audio_config cfg;
+ unsigned sz, n;
+ int fd, afd;
+ unsigned total = 0;
+ unsigned char tmp;
+
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_sz = 0;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = channels;
+ hdr.sample_rate = rate;
+ hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
+ hdr.block_align = hdr.num_channels * 2;
+ hdr.bits_per_sample = 16;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+
+ fd = open(fn, O_CREAT | O_RDWR, 0666);
+ if (fd < 0) {
+ perror("cannot open output file");
+ return -1;
+ }
+ write(fd, &hdr, sizeof(hdr));
+
+ afd = open("/dev/msm_pcm_in", O_RDWR);
+ if (afd < 0) {
+ perror("cannot open msm_pcm_in");
+ close(fd);
+ return -1;
+ }
+
+ /* config change should be a read-modify-write operation */
+ if (ioctl(afd, AUDIO_GET_CONFIG, &cfg)) {
+ perror("cannot read audio config");
+ goto fail;
+ }
+
+ cfg.channel_count = hdr.num_channels;
+ cfg.sample_rate = hdr.sample_rate;
+ if (ioctl(afd, AUDIO_SET_CONFIG, &cfg)) {
+ perror("cannot write audio config");
+ goto fail;
+ }
+
+ if (ioctl(afd, AUDIO_GET_CONFIG, &cfg)) {
+ perror("cannot read audio config");
+ goto fail;
+ }
+
+ sz = cfg.buffer_size;
+ fprintf(stderr,"buffer size %d x %d\n", sz, cfg.buffer_count);
+ if (sz > sizeof(buf)) {
+ fprintf(stderr,"buffer size %d too large\n", sz);
+ goto fail;
+ }
+
+ if (ioctl(afd, AUDIO_START, 0)) {
+ perror("cannot start audio");
+ goto fail;
+ }
+
+ fcntl(0, F_SETFL, O_NONBLOCK);
+ fprintf(stderr,"\n*** RECORDING * HIT ENTER TO STOP ***\n");
+
+ for (;;) {
+ while (read(0, &tmp, 1) == 1) {
+ if ((tmp == 13) || (tmp == 10)) goto done;
+ }
+ if (read(afd, buf, sz) != sz) {
+ perror("cannot read buffer");
+ goto fail;
+ }
+ if (write(fd, buf, sz) != sz) {
+ perror("cannot write buffer");
+ goto fail;
+ }
+ total += sz;
+
+ }
+done:
+ close(afd);
+
+ /* update lengths in header */
+ hdr.data_sz = total;
+ hdr.riff_sz = total + 8 + 16 + 8;
+ lseek(fd, 0, SEEK_SET);
+ write(fd, &hdr, sizeof(hdr));
+ close(fd);
+ return 0;
+
+fail:
+ close(afd);
+ close(fd);
+ unlink(fn);
+ return -1;
+}
+
+int mp3_play(const char *fn)
+{
+ char buf[64*1024];
+ int r;
+ int fd, afd;
+
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ perror("cannot open mp3 file");
+ return -1;
+ }
+
+ afd = open("/dev/msm_mp3", O_RDWR);
+ if (afd < 0) {
+ close(fd);
+ perror("cannot open mp3 output device");
+ return -1;
+ }
+
+ fprintf(stderr,"MP3 PLAY\n");
+ ioctl(afd, AUDIO_START, 0);
+
+ for (;;) {
+ r = read(fd, buf, 64*1024);
+ if (r <= 0) break;
+ r = write(afd, buf, r);
+ if (r < 0) break;
+ }
+
+ close(fd);
+ close(afd);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ const char *fn = 0;
+ int play = 1;
+ unsigned channels = 1;
+ unsigned rate = 44100;
+
+ argc--;
+ argv++;
+ while (argc > 0) {
+ if (!strcmp(argv[0],"-rec")) {
+ play = 0;
+ } else if (!strcmp(argv[0],"-play")) {
+ play = 1;
+ } else if (!strcmp(argv[0],"-stereo")) {
+ channels = 2;
+ } else if (!strcmp(argv[0],"-mono")) {
+ channels = 1;
+ } else if (!strcmp(argv[0],"-rate")) {
+ argc--;
+ argv++;
+ if (argc == 0) {
+ fprintf(stderr,"playwav: -rate requires a parameter\n");
+ return -1;
+ }
+ rate = atoi(argv[0]);
+ } else {
+ fn = argv[0];
+ }
+ argc--;
+ argv++;
+ }
+
+ if (fn == 0) {
+ fn = play ? "/data/out.wav" : "/data/rec.wav";
+ }
+
+ if (play) {
+ const char *dot = strrchr(fn, '.');
+ if (dot && !strcmp(dot,".mp3")) {
+ return mp3_play(fn);
+ } else {
+ return wav_play(fn);
+ }
+ } else {
+ return wav_rec(fn, channels, rate);
+ }
+ return 0;
+}
diff --git a/su/Android.mk b/su/Android.mk
new file mode 100644
index 00000000..dd412d59
--- /dev/null
+++ b/su/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= su.c
+
+LOCAL_MODULE:= su
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+
+LOCAL_STATIC_LIBRARIES := libc
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/su/MODULE_LICENSE_APACHE2 b/su/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/su/MODULE_LICENSE_APACHE2
diff --git a/su/NOTICE b/su/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/su/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/su/su.c b/su/su.c
new file mode 100644
index 00000000..5c9ca106
--- /dev/null
+++ b/su/su.c
@@ -0,0 +1,85 @@
+/*
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <unistd.h>
+#include <time.h>
+
+#include <pwd.h>
+
+/*
+ * SU can be given a specific command to exec. UID _must_ be
+ * specified for this (ie argc => 3).
+ *
+ * Usage:
+ * su 1000
+ * su 1000 ls -l
+ */
+int main(int argc, char **argv)
+{
+ struct passwd *pw;
+ int uid, gid;
+
+ if(argc < 2) {
+ uid = gid = 0;
+ } else {
+ pw = getpwnam(argv[1]);
+
+ if(pw == 0) {
+ uid = gid = atoi(argv[1]);
+ } else {
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ }
+ }
+
+ if(setgid(gid) || setuid(uid)) {
+ fprintf(stderr,"su: permission denied\n");
+ return 1;
+ }
+
+ /* User specified command for exec. */
+ if (argc == 3 ) {
+ if (execlp(argv[2], argv[2], NULL) < 0) {
+ fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2],
+ strerror(errno));
+ return -errno;
+ }
+ } else if (argc > 3) {
+ /* Copy the rest of the args from main. */
+ char *exec_args[argc - 1];
+ memset(exec_args, 0, sizeof(exec_args));
+ memcpy(exec_args, &argv[2], sizeof(exec_args));
+ if (execvp(argv[2], exec_args) < 0) {
+ fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2],
+ strerror(errno));
+ return -errno;
+ }
+ }
+
+ /* Default exec shell. */
+ execlp("/system/bin/sh", "sh", NULL);
+
+ fprintf(stderr, "su: exec failed\n");
+ return 1;
+}
diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100644
index 00000000..582ddc90
--- /dev/null
+++ b/tests/Android.mk
@@ -0,0 +1,3 @@
+ifeq ($(TARGET_ARCH),arm)
+include $(call all-subdir-makefiles)
+endif
diff --git a/tests/bionic/libc/Android.mk b/tests/bionic/libc/Android.mk
new file mode 100644
index 00000000..89d9ade2
--- /dev/null
+++ b/tests/bionic/libc/Android.mk
@@ -0,0 +1,140 @@
+# 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.
+#
+# Build control file for Bionic's test programs
+# define the BIONIC_TESTS environment variable to build the test programs
+#
+ifdef BIONIC_TESTS
+
+LOCAL_PATH:= $(call my-dir)
+
+# used to define a simple test program and build it as a standalone
+# device executable.
+#
+# you can use EXTRA_CFLAGS to indicate additional CFLAGS to use
+# in the build. the variable will be cleaned on exit
+#
+define device-test
+ $(foreach file,$(1), \
+ $(eval include $(CLEAR_VARS)) \
+ $(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_MODULE := $(notdir $(file:%.c=%))) \
+ $(eval $(info LOCAL_MODULE=$(LOCAL_MODULE))) \
+ $(eval LOCAL_CFLAGS += $(EXTRA_CFLAGS)) \
+ $(eval LOCAL_MODULE_TAGS := tests) \
+ $(eval include $(BUILD_EXECUTABLE)) \
+ ) \
+ $(eval EXTRA_CFLAGS :=)
+endef
+
+# same as 'device-test' but builds a host executable instead
+# you can use EXTRA_LDLIBS to indicate additional linker flags
+#
+define host-test
+ $(foreach file,$(1), \
+ $(eval include $(CLEAR_VARS)) \
+ $(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_MODULE := $(notdir $(file:%.c=%))) \
+ $(eval $(info LOCAL_MODULE=$(LOCAL_MODULE) file=$(file))) \
+ $(eval LOCAL_CFLAGS += $(EXTRA_CFLAGS)) \
+ $(eval LOCAL_LDLIBS += $(EXTRA_LDLIBS)) \
+ $(eval LOCAL_MODULE_TAGS := tests) \
+ $(eval include $(BUILD_HOST_EXECUTABLE)) \
+ ) \
+ $(eval EXTRA_CFLAGS :=) \
+ $(eval EXTRA_LDLIBS :=)
+endef
+
+# First, the tests in 'common'
+
+sources := \
+ common/test_gethostbyname.c \
+ common/test_gethostname.c \
+ common/test_pthread_cleanup_push.c \
+ common/test_pthread_getcpuclockid.c \
+ common/test_pthread_join.c \
+ common/test_pthread_once.c \
+ common/test_semaphore.c \
+ common/test_seteuid.c \
+ common/test_static_cpp_mutex.cpp \
+ common/test_tm_zone.c \
+ common/test_udp.c \
+
+EXTRA_LDLIBS := -lpthread -lrt
+$(call host-test, $(sources))
+$(call device-test, $(sources))
+
+sources := \
+ common/test_libgen.c \
+
+EXTRA_CFLAGS := -DHOST
+$(call host-test, $(sources))
+$(call device-test, $(sources))
+
+# Second, the Bionic-specific tests
+
+sources := \
+ bionic/test_mutex.c \
+ bionic/test_cond.c \
+ bionic/test_getgrouplist.c \
+ bionic/test_netinet_icmp.c \
+ bionic/test_pthread_cond.c \
+ bionic/test_pthread_create.c \
+
+$(call device-test, $(sources))
+
+# Third, the other tests
+
+sources := \
+ other/bench_locks.c \
+ other/test_aligned.c \
+ other/test_arc4random.c \
+ other/test_atomics.c \
+ other/test_sysconf.c \
+ other/test_system.c \
+ other/test_thread_max.c \
+ other/test_timer_create.c \
+ other/test_timer_create2.c \
+ other/test_timer_create3.c \
+ other/test_vfprintf_leak.c \
+
+$(call device-test, $(sources))
+
+# The relocations test is a bit special, since we need
+# to build one shared object and one executable that depends
+# on it.
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := bionic/lib_relocs.c
+LOCAL_MODULE := libtest_relocs
+LOCAL_PRELINK_MODULE := false
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := bionic/test_relocs.c
+LOCAL_MODULE := test_relocs
+LOCAL_SHARED_LIBRARIES := libtest_relocs
+include $(BUILD_EXECUTABLE)
+
+# TODO: Add a variety of GLibc test programs too...
+
+# Hello World to test libstdc++ support
+
+sources := \
+ common/hello_world.cpp \
+
+EXTRA_CFLAGS := -mandroid
+#$(call device-test, $(sources))
+
+endif # BIONIC_TESTS
diff --git a/tests/bionic/libc/MODULE_LICENSE_BSD_AND_GPL b/tests/bionic/libc/MODULE_LICENSE_BSD_AND_GPL
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/bionic/libc/MODULE_LICENSE_BSD_AND_GPL
diff --git a/tests/bionic/libc/README.TXT b/tests/bionic/libc/README.TXT
new file mode 100644
index 00000000..5576b77b
--- /dev/null
+++ b/tests/bionic/libc/README.TXT
@@ -0,0 +1,32 @@
+This directory contains a set of tests for Android's Bionic C library.
+
+These sources are not distributed with Bionic itself because some of
+these tests come from the GNU C Library, and are licensed under the
+GNU Lesser General Public License (LGPL)
+
+You must define the BIONIC_TESTS environment variable to build these
+test programs. For example, do:
+
+ cd system/bionic-tests/
+ mm BIONIC_TESTS=1
+
+All test programs, except those in the 'other' directory, should exit
+with a status code of 0 in case of success, and 1 in case of failure.
+
+The directory layout is simple:
+
+ common/
+ Contains tests that can be compiled either with Bionic or another
+ C library.
+
+ glibc/
+ Contains tests that come from the GNU C Library. However, they can
+ be compiled with Bionic too.
+
+ bionic/
+ Contains tests that can *only* be compiled against Bionic
+
+ other/
+ Other unrelated tests. These are not run by the test runner
+ program but will be installed to your device nevertheless.
+ Put benchmarks and various debug/info stuff there.
diff --git a/tests/bionic/libc/bionic/lib_relocs.c b/tests/bionic/libc/bionic/lib_relocs.c
new file mode 100644
index 00000000..af4cf6f8
--- /dev/null
+++ b/tests/bionic/libc/bionic/lib_relocs.c
@@ -0,0 +1,19 @@
+/* this is part of the test_relocs.c test, which is used to check that
+ * the relocations generated in a shared object are properly handled
+ * by the Bionic dynamic linker
+ */
+
+struct foo { int first, second; };
+struct foo Foo = {1, 2};
+
+int* FooPtr[] = { &Foo.first, &Foo.second };
+
+int func1( void )
+{
+ return *FooPtr[0];
+}
+
+int func2( void )
+{
+ return *FooPtr[1];
+}
diff --git a/tests/bionic/libc/bionic/test_cond.c b/tests/bionic/libc/bionic/test_cond.c
new file mode 100644
index 00000000..6a85f9b4
--- /dev/null
+++ b/tests/bionic/libc/bionic/test_cond.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 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 <pthread.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <unistd.h>
+
+static pthread_mutex_t lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
+static pthread_cond_t wait = PTHREAD_COND_INITIALIZER;
+
+static void* _thread1(void *__u __attribute__((unused)))
+{
+ printf("1: obtaining mutex\n");
+ pthread_mutex_lock(&lock);
+ printf("1: waiting on condition variable\n");
+ pthread_cond_wait(&wait, &lock);
+ printf("1: releasing mutex\n");
+ pthread_mutex_unlock(&lock);
+ printf("1: exiting\n");
+ return NULL;
+}
+
+static void* _thread2(void *__u __attribute__((unused)))
+{
+ int cnt = 2;
+ while(cnt--) {
+ printf("2: obtaining mutex\n");
+ pthread_mutex_lock(&lock);
+ printf("2: signaling\n");
+ pthread_cond_signal(&wait);
+ printf("2: releasing mutex\n");
+ pthread_mutex_unlock(&lock);
+ }
+
+ printf("2: exiting\n");
+ return NULL;
+}
+
+typedef void* (*thread_func)(void*);
+static const thread_func thread_routines[] =
+{
+ &_thread1,
+ &_thread2,
+};
+
+int main(void)
+{
+ pthread_t t[2];
+ int nn;
+ int count = (int)(sizeof t/sizeof t[0]);
+
+ for (nn = 0; nn < count; nn++) {
+ printf("main: creating thread %d\n", nn+1);
+ if (pthread_create( &t[nn], NULL, thread_routines[nn], NULL) < 0) {
+ printf("main: could not create thread %d: %s\n", nn+1, strerror(errno));
+ return -2;
+ }
+ }
+
+ for (nn = 0; nn < count; nn++) {
+ printf("main: joining thread %d\n", nn+1);
+ if (pthread_join(t[nn], NULL)) {
+ printf("main: could not join thread %d: %s\n", nn+1, strerror(errno));
+ return -2;
+ }
+ }
+
+ return 0;
+}
diff --git a/tests/bionic/libc/bionic/test_getgrouplist.c b/tests/bionic/libc/bionic/test_getgrouplist.c
new file mode 100644
index 00000000..e5b8ee26
--- /dev/null
+++ b/tests/bionic/libc/bionic/test_getgrouplist.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2008 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 <stdio.h>
+#include <grp.h>
+
+#define MAX_GROUPS 100
+#define TEST_GROUP 1337
+#define TEST_USER "nobodyisreallyhere"
+
+int main(void)
+{
+ int count = MAX_GROUPS;
+ gid_t groups[MAX_GROUPS];
+ int ret;
+
+ /* this only tests the funky behaviour of our stubbed getgrouplist()
+ * implementation. which should only return TEST_GROUP, independent
+ * of the user
+ */
+ ret = getgrouplist( TEST_USER, TEST_GROUP, groups, &count );
+ if (ret != 1) {
+ fprintf(stderr, "getgrouplist() returned %d (expecting 1), ngroups=%d\n",
+ ret, count);
+ return 1;
+ }
+ if (groups[0] != TEST_GROUP) {
+ fprintf(stderr, "getgrouplist() returned group %d (expecting %d)\n",
+ groups[0], TEST_GROUP);
+ return 1;
+ }
+ printf ("ok\n");
+ return 0;
+}
diff --git a/tests/bionic/libc/bionic/test_mutex.c b/tests/bionic/libc/bionic/test_mutex.c
new file mode 100644
index 00000000..02257ba3
--- /dev/null
+++ b/tests/bionic/libc/bionic/test_mutex.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+#define __USE_UNIX98 1 /* necessary to define pthread_mutexattr_set/gettype in Linux GLIBC headers. doh ! */
+#include <pthread.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+static void panic( const char* format, ... )
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ exit(1);
+}
+
+#define assert(cond) do { if ( !(cond) ) panic( "%s:%d: assertion failure: %s\n", __FILE__, __LINE__, #cond ); } while (0)
+
+#define expect(call,result) \
+ do { \
+ int ret = (call); \
+ if (ret != (result)) { \
+ panic( "%s:%d: call returned %d instead of %d: %s\n", \
+ __FILE__, __LINE__, ret, (result), #call ); \
+ } \
+ } while (0)
+
+
+int main( void )
+{
+ pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+ pthread_mutexattr_t attr;
+ int attr_type;
+
+ expect( pthread_mutexattr_init( &attr ), 0 );
+
+ expect( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_NORMAL ), 0 );
+ expect( pthread_mutexattr_gettype( &attr, &attr_type ), 0 );
+ assert( attr_type == PTHREAD_MUTEX_NORMAL );
+
+ expect( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK ), 0 );
+ expect( pthread_mutexattr_gettype( &attr, &attr_type ), 0 );
+ assert( attr_type == PTHREAD_MUTEX_ERRORCHECK );
+
+ expect( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ), 0 );
+ expect( pthread_mutexattr_gettype( &attr, &attr_type ), 0 );
+ assert( attr_type == PTHREAD_MUTEX_RECURSIVE );
+
+ /* standard mutexes */
+ expect( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_NORMAL ), 0 );
+ expect( pthread_mutex_init( &lock, &attr ), 0 );
+ expect( pthread_mutex_lock( &lock ), 0 );
+ expect( pthread_mutex_unlock( &lock ), 0 );
+ expect( pthread_mutex_destroy( &lock ), 0 );
+
+ /* error-check mutex */
+ expect( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK ), 0 );
+ expect( pthread_mutex_init( &lock, &attr ), 0 );
+ expect( pthread_mutex_lock( &lock ), 0 );
+ expect( pthread_mutex_lock( &lock ), EDEADLK );
+ expect( pthread_mutex_unlock( &lock ), 0 );
+ expect( pthread_mutex_trylock( &lock ), 0 );
+ expect( pthread_mutex_trylock( &lock ), EDEADLK );
+ expect( pthread_mutex_unlock( &lock ), 0 );
+ expect( pthread_mutex_unlock( &lock ), EPERM );
+ expect( pthread_mutex_destroy( &lock ), 0 );
+
+ /* recursive mutex */
+ expect( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ), 0 );
+ expect( pthread_mutex_init( &lock, &attr ), 0 );
+ expect( pthread_mutex_lock( &lock ), 0 );
+ expect( pthread_mutex_lock( &lock ), 0 );
+ expect( pthread_mutex_unlock( &lock ), 0 );
+ expect( pthread_mutex_unlock( &lock ), 0 );
+ expect( pthread_mutex_trylock( &lock ), 0 );
+ expect( pthread_mutex_unlock( &lock ), 0 );
+ expect( pthread_mutex_unlock( &lock ), EPERM );
+ expect( pthread_mutex_destroy( &lock ), 0 );
+
+ printf( "ok\n" );
+ return 0;
+}
diff --git a/tests/bionic/libc/bionic/test_netinet_icmp.c b/tests/bionic/libc/bionic/test_netinet_icmp.c
new file mode 100644
index 00000000..308ccce9
--- /dev/null
+++ b/tests/bionic/libc/bionic/test_netinet_icmp.c
@@ -0,0 +1,8 @@
+/* this test simply checks that we can compile the <netinet/ip_icmp.h> header */
+#include <netinet/ip_icmp.h>
+
+int main( void )
+{
+ return 0;
+}
+
diff --git a/tests/bionic/libc/bionic/test_pthread_cond.c b/tests/bionic/libc/bionic/test_pthread_cond.c
new file mode 100644
index 00000000..26746fa7
--- /dev/null
+++ b/tests/bionic/libc/bionic/test_pthread_cond.c
@@ -0,0 +1,83 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+
+static pthread_cond_t cond1;
+static pthread_cond_t cond2;
+static pthread_mutex_t test_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static void *
+thread1_func(void* arg)
+{
+ printf("Thread 1 (arg=%d tid=%d) entered.\n", (unsigned)arg, gettid());
+ printf("1 waiting for cond1\n");
+ pthread_mutex_lock(&test_lock);
+ pthread_cond_wait(&cond1, &test_lock );
+ pthread_mutex_unlock(&test_lock);
+ printf("Thread 1 done.\n");
+ return 0;
+}
+
+static void *
+thread2_func(void* arg)
+{
+ printf("Thread 2 (arg=%d tid=%d) entered.\n", (unsigned)arg, gettid());
+ printf("2 waiting for cond2\n");
+ pthread_mutex_lock(&test_lock);
+ pthread_cond_wait(&cond2, &test_lock );
+ pthread_mutex_unlock(&test_lock);
+
+ printf("Thread 2 done.\n");
+ return 0;
+}
+
+static void *
+thread3_func(void* arg)
+{
+ printf("Thread 3 (arg=%d tid=%d) entered.\n", (unsigned)arg, gettid());
+ printf("3 waiting for cond1\n");
+ pthread_mutex_lock(&test_lock);
+ pthread_cond_wait(&cond1, &test_lock );
+ pthread_mutex_unlock(&test_lock);
+ printf("3 Sleeping\n");
+ sleep(2);
+ printf("3 signal cond2\n");
+ pthread_cond_signal(&cond2);
+
+ printf("Thread 3 done.\n");
+ return 0;
+}
+
+static void *
+thread4_func(void* arg)
+{
+ printf("Thread 4 (arg=%d tid=%d) entered.\n", (unsigned)arg, gettid());
+ printf("4 Sleeping\n");
+ sleep(5);
+
+ printf("4 broadcast cond1\n");
+ pthread_cond_broadcast(&cond1);
+ printf("Thread 4 done.\n");
+ return 0;
+}
+
+int main(int argc, const char *argv[])
+{
+ pthread_t t[4];
+
+ pthread_cond_init(&cond1, NULL);
+ pthread_cond_init(&cond2, NULL);
+ pthread_create( &t[0], NULL, thread1_func, (void *)1 );
+ pthread_create( &t[1], NULL, thread2_func, (void *)2 );
+ pthread_create( &t[2], NULL, thread3_func, (void *)3 );
+ pthread_create( &t[3], NULL, thread4_func, (void *)4 );
+
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ pthread_join(t[2], NULL);
+ pthread_join(t[3], NULL);
+ return 0;
+}
diff --git a/tests/bionic/libc/bionic/test_pthread_create.c b/tests/bionic/libc/bionic/test_pthread_create.c
new file mode 100644
index 00000000..edac0ff1
--- /dev/null
+++ b/tests/bionic/libc/bionic/test_pthread_create.c
@@ -0,0 +1,30 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static void *
+thread1_func(void* arg)
+{
+ printf("Thread 1 (arg=%d tid=%d) entered.\n", (unsigned)arg, gettid());
+ return 0;
+}
+
+static void *
+thread2_func(void* arg)
+{
+ printf("thread 2 (arg=%d tid=%d) entered.\n", (unsigned)arg, gettid());
+ return 1;
+}
+
+
+int main( void )
+{
+ pthread_t t1, t2;
+
+ pthread_create( &t1, NULL, thread1_func, (void *)1 );
+
+ pthread_join(t1, NULL);
+
+ printf("OK\n");
+ return 0;
+}
diff --git a/tests/bionic/libc/bionic/test_relocs.c b/tests/bionic/libc/bionic/test_relocs.c
new file mode 100644
index 00000000..c42df116
--- /dev/null
+++ b/tests/bionic/libc/bionic/test_relocs.c
@@ -0,0 +1,25 @@
+/* this little test is written to check that the relocations generated
+ * in a shared library are correct. it depends on the content of lib_relocs.c
+ * being compiled as a shared object.
+ */
+#include <stdio.h>
+
+extern int func1(void);
+extern int func2(void);
+
+int
+main( void )
+{
+ int f1, f2, expect1 = 1, expect2 = 2;
+
+ f1 = func1();
+ f2 = func2();
+
+ printf( "func1() returns %d: %s\n", f1, (f1 == expect1) ? "OK" : "FAIL" );
+ printf( "func2() returns %d: %s\n", f2, (f2 == expect2) ? "OK" : "FAIL" );
+
+ if (f1 != expect1 || f2 != expect2)
+ return 1;
+
+ return 0;
+}
diff --git a/tests/bionic/libc/common/hello_world.cpp b/tests/bionic/libc/common/hello_world.cpp
new file mode 100644
index 00000000..0578d7d8
--- /dev/null
+++ b/tests/bionic/libc/common/hello_world.cpp
@@ -0,0 +1,8 @@
+#include <iostream>
+using namespace std;
+
+int main()
+{
+ cout << "Hello World" << endl;
+ return 0;
+}
diff --git a/tests/bionic/libc/common/test_gethostbyname.c b/tests/bionic/libc/common/test_gethostbyname.c
new file mode 100644
index 00000000..1e932d60
--- /dev/null
+++ b/tests/bionic/libc/common/test_gethostbyname.c
@@ -0,0 +1,53 @@
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netdb.h>
+
+int main( int argc, char** argv )
+{
+ char* hostname = "localhost";
+ struct hostent* hent;
+ int i, ret;
+
+ if (argc > 1)
+ hostname = argv[1];
+
+ hent = gethostbyname(hostname);
+ if (hent == NULL) {
+ printf("gethostbyname(%s) returned NULL !!\n", hostname);
+ return 1;
+ }
+ printf( "gethostbyname(%s) returned:\n", hostname);
+ printf( " name: %s\n", hent->h_name );
+ printf( " aliases:" );
+ for (i = 0; hent->h_aliases[i] != NULL; i++)
+ printf( " %s", hent->h_aliases[i] );
+ printf( "\n" );
+ printf( " address type: " );
+ switch (hent->h_addrtype) {
+ case AF_INET: printf( "AF_INET\n"); break;
+ case AF_INET6: printf( "AF_INET6\n"); break;
+ default: printf("UNKNOWN (%d)\n", hent->h_addrtype);
+ }
+ printf( " address: " );
+ switch (hent->h_addrtype) {
+ case AF_INET:
+ {
+ const char* dot = "";
+ for (i = 0; i < hent->h_length; i++) {
+ printf("%s%d", dot, ((unsigned char*)hent->h_addr)[i]);
+ dot = ".";
+ }
+ }
+ break;
+
+ default:
+ for (i = 0; i < hent->h_length; i++) {
+ printf( "%02x", ((unsigned char*)hent->h_addr)[i] );
+ }
+ }
+ printf("\n");
+ return 0;
+}
diff --git a/tests/bionic/libc/common/test_gethostname.c b/tests/bionic/libc/common/test_gethostname.c
new file mode 100644
index 00000000..b9dcbafc
--- /dev/null
+++ b/tests/bionic/libc/common/test_gethostname.c
@@ -0,0 +1,20 @@
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+int main( void )
+{
+ char hostname[512];
+ int ret;
+
+ ret = gethostname(hostname, sizeof(hostname));
+ if (ret < 0) {
+ printf("gethostname() returned error %d: %s\n", errno, strerror(errno));
+ return 1;
+ }
+
+ printf("gethostname() returned '%s'\n", hostname);
+ return 0;
+}
diff --git a/tests/bionic/libc/common/test_libgen.c b/tests/bionic/libc/common/test_libgen.c
new file mode 100644
index 00000000..4a2c29e2
--- /dev/null
+++ b/tests/bionic/libc/common/test_libgen.c
@@ -0,0 +1,221 @@
+// test the basename, dirname, basename_r and dirname_r
+#include <libgen.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+static int fail = 0;
+
+static void
+test_basename(char* _input, const char* _expected, int _errno)
+{
+ char temp[256], *input = _input;
+ char* ret;
+#if HOST
+ /* GLibc does modify the input string. bummer */
+ if (_input) {
+ strcpy(temp, _input);
+ input = temp;
+ }
+#endif
+ errno = 0;
+ ret = basename(input);
+ if (_expected == NULL) {
+ if (ret != NULL) {
+ fprintf(stderr,
+ "KO: basename(\"%s\") returned \"%s\", NULL expected)\n",
+ _input, ret);
+ fail += 1;
+ } else if (errno != _errno) {
+ fprintf(stderr,
+ "KO: basename(\"%s\") returned NULL with error: %d (%d expected)\n",
+ _input, errno, _errno);
+ fail += 1;
+ } else {
+ printf( "OK: basename(\"%s\") returned NULL with error %d\n",
+ _input, _errno );
+ }
+ } else {
+ if (ret == NULL) {
+ fprintf(stderr, "KO: basename(\"%s\") returned NULL with error %d\n",
+ _input, errno);
+ fail += 1;
+ }
+ else if (strcmp(ret, _expected)) {
+ fprintf(stderr, "KO: basename(\"%s\") returned \"%s\", instead of \"%s\"\n",
+ _input, ret, _expected);
+ }
+ else {
+ printf( "OK: basename(\"%s\") returned \"%s\"\n",
+ _input, ret );
+ }
+ }
+}
+
+
+#if !HOST
+static void
+test_basename_r(char* _input, const char* _expected_content, int _expected, char* _buff, size_t _bufflen, int _errno)
+{
+ int ret;
+ errno = 0;
+ ret = basename_r(_input, _buff, _bufflen );
+ if (ret != _expected) {
+ fprintf(stderr,
+ "KO: basename_r(\"%s\", <buff>, %d) returned %d (expected %d)\n",
+ _input, _bufflen, ret, _expected);
+ fail += 1;
+ return;
+ }
+ if (ret == -1) {
+ if (errno != _errno) {
+ fprintf(stderr,
+ "KO: basename_r(\"%s\", <buff>, %d) returned -1 with errno=%d (expected %d)\n",
+ _input, _bufflen, errno, _errno);
+ fail += 1;
+ return;
+ }
+ }
+ else if ( memcmp( _buff, _expected_content, ret ) ) {
+ fprintf(stderr,
+ "KO: basename_r(\"%s\", <buff>, %d) returned \"%s\", expected \"%s\"\n",
+ _input, _bufflen, _buff, _expected_content );
+ fail += 1;
+ return;
+ }
+ printf("OK: basename_r(\"%s\", <buff>, %d) returned \"%s\"\n",
+ _input, _bufflen, _expected_content );
+}
+
+static void
+test_dirname_r(char* _input, const char* _expected_content, int _expected, char* _buff, size_t _bufflen, int _errno)
+{
+ int ret;
+ errno = 0;
+ ret = dirname_r(_input, _buff, _bufflen );
+ if (ret != _expected) {
+ fprintf(stderr,
+ "KO: dirname_r(\"%s\", <buff>, %d) returned %d (expected %d)\n",
+ _input, _bufflen, ret, _expected);
+ fail += 1;
+ return;
+ }
+ if (ret == -1) {
+ if (errno != _errno) {
+ fprintf(stderr,
+ "KO: dirname_r(\"%s\", <buff>, %d) returned -1 with errno=%d (expected %d)\n",
+ _input, _bufflen, errno, _errno);
+ fail += 1;
+ return;
+ }
+ }
+ else if ( memcmp( _buff, _expected_content, ret ) ) {
+ fprintf(stderr,
+ "KO: dirname_r(\"%s\", <buff>, %d) returned \"%s\", expected \"%s\"\n",
+ _input, _bufflen, _buff, _expected_content );
+ fail += 1;
+ return;
+ }
+ printf("OK: dirname_r(\"%s\", <buff>, %d) returned \"%s\"\n",
+ _input, _bufflen, _expected_content );
+}
+#endif
+
+
+static void
+test_dirname(char* _input, const char* _expected, int _errno)
+{
+ char temp[256], *input = _input;
+ char* ret;
+#if HOST
+ /* GLibc does modify the input string. bummer */
+ if (_input) {
+ strcpy(temp, _input);
+ input = temp;
+ }
+#endif
+ errno = 0;
+ ret = dirname(input);
+ if (_expected == NULL) {
+ if (ret != NULL) {
+ fprintf(stderr,
+ "KO: dirname(\"%s\") returned \"%s\", NULL expected)\n",
+ _input, ret);
+ fail += 1;
+ } else if (errno != _errno) {
+ fprintf(stderr,
+ "KO: dirname(\"%s\") returned NULL with error: %d (%d expected)\n",
+ _input, errno, _errno);
+ fail += 1;
+ } else {
+ printf( "OK: dirname(\"%s\") returned NULL with error %d\n",
+ _input, _errno );
+ }
+ } else {
+ if (ret == NULL) {
+ fprintf(stderr, "KO: dirname(\"%s\") returned NULL with error %d\n",
+ _input, errno);
+ fail += 1;
+ }
+ else if (strcmp(ret, _expected)) {
+ fprintf(stderr, "KO: dirname(\"%s\") returned \"%s\", instead of \"%s\"\n",
+ _input, ret, _expected);
+ }
+ else {
+ printf( "OK: dirname(\"%s\") returned \"%s\"\n",
+ _input, ret );
+ }
+ }
+}
+
+
+
+
+int main( void )
+{
+ char buff[256];
+
+ test_basename( "", ".", 0 );
+ test_basename( "/usr/lib", "lib", 0 );
+ test_basename( "/usr/", "usr", 0 );
+ test_basename( "usr", "usr", 0 );
+ test_basename( "/", "/", 0 );
+ test_basename( ".", ".", 0 );
+ test_basename( "..", "..", 0 );
+
+#if !HOST
+ test_basename_r( "", ".", 1, NULL, 0, 0 );
+ test_basename_r( "", ".", -1, buff, 0, ERANGE );
+ test_basename_r( "", ".", -1, buff, 1, ERANGE );
+ test_basename_r( "", ".", 1, buff, 2, 0 );
+ test_basename_r( "", ".", 1, buff, sizeof(buff), 0 );
+ test_basename_r( "/usr/lib", "lib", 3, buff, sizeof(buff), 0 );
+ test_basename_r( "/usr/", "usr", 3, buff, sizeof(buff), 0 );
+ test_basename_r( "usr", "usr", 3, buff, sizeof(buff), 0 );
+ test_basename_r( "/", "/", 1, buff, sizeof(buff), 0 );
+ test_basename_r( ".", ".", 1, buff, sizeof(buff), 0 );
+ test_basename_r( "..", "..", 2, buff, sizeof(buff), 0 );
+#endif
+
+ test_dirname( "", ".", 0 );
+ test_dirname( "/usr/lib", "/usr", 0 );
+ test_dirname( "/usr/", "/", 0 );
+ test_dirname( "usr", ".", 0 );
+ test_dirname( ".", ".", 0 );
+ test_dirname( "..", ".", 0 );
+
+#if !HOST
+ test_dirname_r( "", ".", 1, NULL, 0, 0 );
+ test_dirname_r( "", ".", -1, buff, 0, ERANGE );
+ test_dirname_r( "", ".", -1, buff, 1, ERANGE );
+ test_dirname_r( "", ".", 1, buff, 2, 0 );
+ test_dirname_r( "/usr/lib", "/usr", 4, buff, sizeof(buff), 0 );
+ test_dirname_r( "/usr/", "/", 1, buff, sizeof(buff), 0 );
+ test_dirname_r( "usr", ".", 1, buff, sizeof(buff), 0 );
+ test_dirname_r( ".", ".", 1, buff, sizeof(buff), 0 );
+ test_dirname_r( "..", ".", 1, buff, sizeof(buff), 0 );
+#endif
+
+ return (fail > 0);
+}
+
diff --git a/tests/bionic/libc/common/test_pthread_cleanup_push.c b/tests/bionic/libc/common/test_pthread_cleanup_push.c
new file mode 100644
index 00000000..87634adf
--- /dev/null
+++ b/tests/bionic/libc/common/test_pthread_cleanup_push.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2008 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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#define MAGIC1 0xcafebabeU
+#define MAGIC2 0x8badf00dU
+#define MAGIC3 0x12345667U
+
+static int g_ok1 = 0;
+static int g_ok2 = 0;
+static int g_ok3 = 0;
+
+static void
+cleanup1( void* arg )
+{
+ if ((unsigned)arg != MAGIC1)
+ g_ok1 = -1;
+ else
+ g_ok1 = +1;
+}
+
+static void
+cleanup2( void* arg )
+{
+ if ((unsigned)arg != MAGIC2) {
+ g_ok2 = -1;
+ } else
+ g_ok2 = +1;
+}
+
+static void
+cleanup3( void* arg )
+{
+ if ((unsigned)arg != MAGIC3)
+ g_ok3 = -1;
+ else
+ g_ok3 = +1;
+}
+
+
+static void*
+thread1_func( void* arg )
+{
+ pthread_cleanup_push( cleanup1, (void*)MAGIC1 );
+ pthread_cleanup_push( cleanup2, (void*)MAGIC2 );
+ pthread_cleanup_push( cleanup3, (void*)MAGIC3 );
+
+ if (arg != NULL)
+ pthread_exit(0);
+
+ pthread_cleanup_pop(0);
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+
+ return NULL;
+}
+
+static int test( int do_exit )
+{
+ pthread_t t;
+
+ pthread_create( &t, NULL, thread1_func, (void*)do_exit );
+ pthread_join( t, NULL );
+
+ if (g_ok1 != +1) {
+ if (g_ok1 == 0) {
+ fprintf(stderr, "cleanup1 not called !!\n");
+ } else {
+ fprintf(stderr, "cleanup1 called with wrong argument\n" );
+ }
+ exit(1);
+ }
+ else if (g_ok2 != +1) {
+ if (g_ok2 == 0)
+ fprintf(stderr, "cleanup2 not called !!\n");
+ else
+ fprintf(stderr, "cleanup2 called with wrong argument\n");
+ exit(2);
+ }
+ else if (do_exit && g_ok3 != +1) {
+ if (g_ok3 == 0) {
+ fprintf(stderr, "cleanup3 not called !!\n");
+ } else {
+ fprintf(stderr, "cleanup3 called with bad argument !!\n");
+ }
+ exit(3);
+ }
+ else if (!do_exit && g_ok3 != 0) {
+ if (g_ok3 == 1) {
+ fprintf(stderr, "cleanup3 wrongly called !!\n");
+ } else {
+ fprintf(stderr, "cleanup3 wrongly called with bad argument !!\n");
+ }
+ exit(3);
+ }
+
+ return 0;
+}
+
+int main( void )
+{
+ test(0);
+ test(1);
+ printf("OK\n");
+ return 0;
+}
diff --git a/tests/bionic/libc/common/test_pthread_getcpuclockid.c b/tests/bionic/libc/common/test_pthread_getcpuclockid.c
new file mode 100644
index 00000000..2a828088
--- /dev/null
+++ b/tests/bionic/libc/common/test_pthread_getcpuclockid.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+/* this is a small test for pthread_getcpuclockid() and clock_gettime() */
+
+#include <time.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+static void*
+thread_func( void* arg )
+{
+ pthread_t self = pthread_self();
+ struct timespec ts;
+ clockid_t clock;
+ int e;
+
+ pthread_mutex_lock( &lock );
+
+ e = pthread_getcpuclockid( self, &clock );
+ if (e != 0) {
+ fprintf(stderr, "pthread_getcpuclockid(%08lx,) returned error %d: %s\n", self, e, strerror(e));
+ pthread_mutex_unlock( &lock );
+ return NULL;
+ }
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 300000000 + ((int)arg)*50000000;
+ nanosleep( &ts, &ts );
+
+ clock_gettime( clock, &ts );
+ fprintf(stderr, "thread %08lx: clock_gettime() returned %g nsecs\n", self, ts.tv_sec*1e9 + ts.tv_nsec);
+
+ pthread_mutex_unlock( &lock );
+
+ return NULL;
+}
+
+#define MAX_THREADS 16
+
+int main( void )
+{
+ int nn;
+ pthread_attr_t attr;
+ pthread_t threads[MAX_THREADS];
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ for (nn = 0; nn < MAX_THREADS; nn++) {
+ pthread_create( &threads[nn], &attr, thread_func, (void*)nn );
+ }
+ for (nn = 0; nn < MAX_THREADS; nn++) {
+ void* dummy;
+ pthread_join( threads[nn], &dummy );
+ }
+ return 0;
+}
diff --git a/tests/bionic/libc/common/test_pthread_join.c b/tests/bionic/libc/common/test_pthread_join.c
new file mode 100644
index 00000000..4fe2561a
--- /dev/null
+++ b/tests/bionic/libc/common/test_pthread_join.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 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 <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static void*
+thread1_func(void* arg)
+{
+ usleep( 2000*1000 );
+ printf("thread 1 exited\n");
+ return (void*) 0x8badf00d;
+}
+
+static void*
+thread2_func(void* arg)
+{
+ pthread_t t1 = (pthread_t)arg;
+ void* result;
+
+ pthread_join(t1, &result);
+ printf("thread2 received code %08x from thread1\n", (int)result);
+ return NULL;
+}
+
+
+static void*
+thread3_func(void* arg)
+{
+ pthread_t t1 = (pthread_t)arg;
+ void* result;
+
+ pthread_join(t1, &result);
+ printf("thread3 received code %08x from thread1\n", (int)result);
+ return NULL;
+}
+
+int main( void )
+{
+ pthread_t t1, t2, t3;
+
+ pthread_create( &t1, NULL, thread1_func, NULL );
+ pthread_create( &t2, NULL, thread2_func, (void*)t1 );
+ pthread_create( &t3, NULL, thread3_func, (void*)t1 );
+
+ pthread_join(t2, NULL);
+ pthread_join(t3, NULL);
+
+ printf("OK\n");
+ return 0;
+}
diff --git a/tests/bionic/libc/common/test_pthread_once.c b/tests/bionic/libc/common/test_pthread_once.c
new file mode 100644
index 00000000..3beda913
--- /dev/null
+++ b/tests/bionic/libc/common/test_pthread_once.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2008 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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define N_THREADS 100
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+static int global_count = 0;
+
+static void
+once_function( void )
+{
+ struct timespec ts;
+
+ global_count += 1;
+
+ ts.tv_sec = 2;
+ ts.tv_nsec = 0;
+ nanosleep (&ts, NULL);
+}
+
+static void*
+thread_function(void* arg)
+{
+ pthread_once( &once, once_function );
+
+ if (global_count != 1) {
+ printf ("thread %ld: global == %d\n", (long int) arg, global_count);
+ exit (1);
+ }
+ return NULL;
+}
+
+int main( void )
+{
+ pthread_t threads[N_THREADS];
+ int nn;
+
+ for (nn = 0; nn < N_THREADS; nn++) {
+ if (pthread_create( &threads[nn], NULL, thread_function, (void*)(long int)nn) < 0) {
+ printf("creation of thread %d failed\n", nn);
+ return 1;
+ }
+ }
+
+ for (nn = 0; nn < N_THREADS; nn++) {
+ if (pthread_join(threads[nn], NULL)) {
+ printf("joining thread %d failed\n", nn);
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/tests/bionic/libc/common/test_semaphore.c b/tests/bionic/libc/common/test_semaphore.c
new file mode 100644
index 00000000..6792d861
--- /dev/null
+++ b/tests/bionic/libc/common/test_semaphore.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2008 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 <pthread.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <unistd.h>
+
+/* a simple semaphore test, using three threads
+ *
+ * a semaphore is initialized with a value of 1
+ *
+ * Thread 1, 2 and 3 start at the same time
+ *
+ * Thread 1 takes the semaphore, then sleeps for 2 seconds, then post the semaphore
+ * Thread 2 sleeps for 1 second, then waits the semaphore, sleeps for 2 seconds, then post the semaphoe
+ * Thread 3 sleeps 3 seconds, waits for the semaphore
+ */
+
+static sem_t semaphore;
+
+static void*
+_thread1( void* unused )
+{
+ printf( "thread 1: waiting for semaphore\n" );
+ if ( sem_wait( &semaphore ) < 0 ) {
+ printf( "thread 1: could not wait for semaphore: %s\n", strerror(errno) );
+ return NULL;
+ }
+ printf( "thread 1: got the semaphore ! sleeping for 2 seconds\n" );
+ sleep( 2 );
+ printf( "thread 1: awake !! posting semaphore\n" );
+ if ( sem_post( &semaphore ) < 0 ) {
+ printf( "thread 2: could not post semaphore: %s\n", strerror(errno) );
+ }
+ printf( "thread 1: quitting\n" );
+ return NULL;
+}
+
+static void*
+_thread2( void* unused )
+{
+ printf( "thread 2: sleeping for 1 second\n" );
+ sleep(1);
+ printf( "thread 2: awake !! waiting for semaphore\n" );
+ if ( sem_wait( &semaphore ) < 0 ) {
+ printf( "thread 2: could not wait for semaphore: %s\n", strerror(errno) );
+ return NULL;
+ }
+ printf( "thread 2: got the semaphore ! sleeping for 2 seconds\n" );
+ sleep( 2 );
+ printf( "thread 2: awake !! posting semaphore\n" );
+ if ( sem_post( &semaphore ) < 0 ) {
+ printf( "thread 2: could not post semaphore: %s\n", strerror(errno) );
+ }
+ printf( "thread 2: quitting\n" );
+ return NULL;
+}
+
+
+static void*
+_thread3( void* unused )
+{
+ printf( "thread 3: sleeping for 3 seconds\n" );
+ sleep(3);
+ printf( "thread 3: awake !! waiting for semaphore\n" );
+ if ( sem_wait( &semaphore ) < 0 ) {
+ printf( "thread 3: could not wait for semaphore: %s\n", strerror(errno) );
+ return NULL;
+ }
+ printf( "thread 3: got semaphore. quitting\n" );
+ return NULL;
+}
+
+typedef void* (*thread_func)(void*);
+
+static const thread_func thread_routines[] =
+{
+ &_thread1,
+ &_thread2,
+ &_thread3
+};
+
+int main( void )
+{
+ pthread_t t[3];
+ int nn;
+
+ if ( sem_init( &semaphore, 0, 1 ) < 0 ) {
+ printf( "could not initialize semaphore: %s\n", strerror(errno) );
+ return -1;
+ }
+
+ for ( nn = 0; nn < 3; nn++ ) {
+ if ( pthread_create( &t[nn], NULL, thread_routines[nn], NULL ) < 0 ) {
+ printf("could not create thread %d: %s\n", nn+1, strerror(errno) );
+ return -2;
+ }
+ }
+ sleep( 5 );
+ return 0;
+}
diff --git a/tests/bionic/libc/common/test_seteuid.c b/tests/bionic/libc/common/test_seteuid.c
new file mode 100644
index 00000000..ac330cec
--- /dev/null
+++ b/tests/bionic/libc/common/test_seteuid.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 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 <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+int main( void )
+{
+ uid_t ruid, euid;
+
+ printf( "sizeof(uid_t) = %d sizeof(gid_t) = %d\n", sizeof(uid_t), sizeof(gid_t) );
+
+ ruid = getuid();
+ euid = geteuid();
+ printf("Start: ruid=%d euid=%d\n", ruid, euid);
+
+ if (seteuid(9999) != 0)
+ perror("seteuid(9999)");
+
+ ruid = getuid();
+ euid = geteuid();
+ printf("After set: ruid=%d euid=%d\n", ruid, euid);
+
+ if (seteuid(0) != 0)
+ perror("seteuid(0)");
+
+ ruid = getuid();
+ euid = geteuid();
+ printf("After restore: ruid=%d euid=%d\n", ruid, euid);
+
+ return 0;
+}
diff --git a/tests/bionic/libc/common/test_static_cpp_mutex.cpp b/tests/bionic/libc/common/test_static_cpp_mutex.cpp
new file mode 100644
index 00000000..33a56ef4
--- /dev/null
+++ b/tests/bionic/libc/common/test_static_cpp_mutex.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+/* this program is used to test the locking of a recursive mutex in a static C++ constructor
+ * this operation crashes on some
+ */
+#include <pthread.h>
+#include <stdio.h>
+
+class Foo {
+private:
+ pthread_mutex_t mMutex;
+public:
+ virtual int getValue();
+ Foo();
+};
+
+Foo::Foo()
+{
+ pthread_mutexattr_t mattr;
+
+ pthread_mutexattr_init(&mattr);
+ pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mMutex, &mattr);
+ pthread_mutex_lock(&mMutex);
+ fprintf(stderr, "recursive lock initialized and locked\n" );
+}
+
+int Foo::getValue()
+{
+ return 0;
+}
+
+static Foo f;
+
+int main(void)
+{
+ printf( "f.getValue() returned: %d\n", f.getValue() );
+ return 0;
+}
diff --git a/tests/bionic/libc/common/test_tm_zone.c b/tests/bionic/libc/common/test_tm_zone.c
new file mode 100644
index 00000000..63e06353
--- /dev/null
+++ b/tests/bionic/libc/common/test_tm_zone.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+/* a small program to test the tm_zone setting in Bionic */
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main( void )
+{
+#ifndef TM_ZONE
+ fprintf(stderr, "TM_ZONE is not defined in <time.h> !!\n" );
+ return 1;
+#else
+ const char* tz = getenv("TZ");
+ time_t now = time(NULL);
+ struct tm tm0;
+ struct tm* tm;
+
+ if (tz) {
+ printf( "TZ set to '%s'\n", tz );
+ } else
+ printf( "TZ is not defined\n" );
+
+ tm = localtime_r( &now, &tm0 );
+ printf( "localtime_r() returns timezone abbreviation '%s'\n", tm->TM_ZONE ? tm->TM_ZONE : "<NULL POINTER>" );
+ printf( "tzname[0] is '%s'\n", tzname[0] ? tzname[0] : "<NULL POINTER>" );
+ printf( "tzname[1] is '%s'\n", tzname[1] ? tzname[1] : "<NULL POINTER>" );
+#endif
+ return 0;
+}
diff --git a/tests/bionic/libc/common/test_udp.c b/tests/bionic/libc/common/test_udp.c
new file mode 100644
index 00000000..3c9dd079
--- /dev/null
+++ b/tests/bionic/libc/common/test_udp.c
@@ -0,0 +1,121 @@
+/* this program is used to test UDP networking in Android.
+ * used to debug the emulator's networking implementation
+ */
+#define PROGNAME "test_udp"
+#define DEFAULT_PORT 7000
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <string.h>
+
+#define BUFLEN 512
+#define NPACK 10
+
+void diep(char *s)
+{
+ perror(s);
+ exit(1);
+}
+
+static void
+usage(int code)
+{
+ printf("usage: %s [options]\n", PROGNAME);
+ printf("options:\n");
+ printf(" -p<port> use specific port (default %d)\n", DEFAULT_PORT);
+ printf(" -a<inet> use specific IP address\n");
+ printf(" -s run server (default is client)\n");
+ exit(code);
+}
+
+int main(int argc, char** argv)
+{
+ int runServer = 0;
+ int udpPort = DEFAULT_PORT;
+ int useLocal = 0;
+ int address = htonl(INADDR_ANY);
+
+ struct sockaddr_in si_me, si_other;
+ int s, i, slen=sizeof(si_other);
+ char buf[BUFLEN];
+
+ while (argc > 1 && argv[1][0] == '-') {
+ const char* optName = argv[1]+1;
+ argc--;
+ argv++;
+
+ switch (optName[0]) {
+ case 'p':
+ udpPort = atoi(optName+1);
+ if (udpPort < 1024 || udpPort > 65535) {
+ fprintf(stderr, "UDP port must be between 1024 and 65535\n");
+ exit(1);
+ }
+ break;
+
+ case 's':
+ runServer = 1;
+ break;
+
+ case 'a':
+ if (inet_aton(optName+1, &si_other.sin_addr) == 0)
+ diep("inet_aton");
+ address = si_other.sin_addr.s_addr;
+ break;
+
+ default:
+ usage(1);
+ }
+ }
+
+ if (runServer) {
+ if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
+ diep("socket");
+
+ memset((char *) &si_me, 0, sizeof(si_me));
+ si_me.sin_family = AF_INET;
+ si_me.sin_port = htons(udpPort);
+ si_me.sin_addr.s_addr = address;
+ if (bind(s, (struct sockaddr*)&si_me, sizeof(si_me))==-1)
+ diep("bind");
+
+ printf("UDP server listening on %s:%d\n", inet_ntoa(si_me.sin_addr), udpPort);
+ for (i=0; i<NPACK; i++) {
+ if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr*)&si_other, (socklen_t*)&slen)==-1)
+ diep("recvfrom()");
+ printf("Received packet from %s:%d\nData: %s\n\n",
+ inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), buf);
+ }
+
+ printf("UDP server closing\n");
+ close(s);
+ }
+ else /* !runServer */
+ {
+ if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
+ diep("socket");
+
+ memset((char *) &si_other, 0, sizeof(si_other));
+ si_other.sin_family = AF_INET;
+ si_other.sin_port = htons(udpPort);
+ si_other.sin_addr.s_addr = address;
+
+ printf("UDP client sending packets to %s:%d\n", inet_ntoa(si_other.sin_addr), udpPort);
+
+ for (i=0; i<NPACK; i++) {
+ printf("Sending packet %d\n", i);
+ sprintf(buf, "This is packet %d\n", i);
+ if (sendto(s, buf, BUFLEN, 0, (struct sockaddr*)&si_other, slen)==-1)
+ diep("sendto()");
+ }
+
+ close(s);
+ printf("UDP client closing\n");
+ }
+ return 0;
+}
diff --git a/tests/bionic/libc/glibc/assert/test-assert.c b/tests/bionic/libc/glibc/assert/test-assert.c
new file mode 100644
index 00000000..26b58d4d
--- /dev/null
+++ b/tests/bionic/libc/glibc/assert/test-assert.c
@@ -0,0 +1,88 @@
+/* Test assert().
+ *
+ * This is hairier than you'd think, involving games with
+ * stdio and signals.
+ *
+ */
+
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+
+jmp_buf rec;
+char buf[160];
+
+static void
+sigabrt (int unused)
+{
+ longjmp (rec, 1); /* recover control */
+}
+
+#undef NDEBUG
+#include <assert.h>
+static void
+assert1 (void)
+{
+ assert (1 == 2);
+}
+
+static void
+assert2 (void)
+{
+ assert (1 == 1);
+}
+
+
+#define NDEBUG
+#include <assert.h>
+static void
+assert3 (void)
+{
+ assert (2 == 3);
+}
+
+int
+main (void)
+{
+
+ volatile int failed = 1;
+
+ fclose (stderr);
+ stderr = tmpfile ();
+ if(!stderr)
+ abort ();
+
+ signal (SIGABRT, sigabrt);
+
+ if (!setjmp (rec))
+ assert1 ();
+ else
+ failed = 0; /* should happen */
+
+ if (!setjmp (rec))
+ assert2 ();
+ else
+ failed = 1; /* should not happen */
+
+ if (!setjmp (rec))
+ assert3 ();
+ else
+ failed = 1; /* should not happen */
+
+ rewind (stderr);
+ fgets (buf, 160, stderr);
+ if (!strstr (buf, "1 == 2"))
+ failed = 1;
+
+ fgets (buf, 160, stderr);
+ if (strstr (buf, "1 == 1"))
+ failed = 1;
+
+ fgets (buf, 160, stderr);
+ if (strstr (buf, "2 == 3"))
+ failed = 1;
+
+ return failed;
+}
diff --git a/tests/bionic/libc/other/bench_locks.c b/tests/bionic/libc/other/bench_locks.c
new file mode 100644
index 00000000..87b1c4c1
--- /dev/null
+++ b/tests/bionic/libc/other/bench_locks.c
@@ -0,0 +1,32 @@
+/* a small program to benchmark locking primitives with different implementations */
+
+#include <pthread.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+static double now(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec + tv.tv_usec/1000000.0;
+}
+
+int main( void )
+{
+ double t0, t1;
+ pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
+ int volatile lock2 = 0;
+ long count;
+ const long ITERATIONS = 1000000;
+
+ /* pthread_mutex_lock */
+ t0 = now();
+ for (count = ITERATIONS; count > 0; count--) {
+ pthread_mutex_lock(&lock1);
+ pthread_mutex_unlock(&lock1);
+ }
+ t1 = now() - t0;
+ printf( "pthread_mutex_lock/unlock: %.5g us/op\n", (t1*1000000.0)/ITERATIONS );
+
+ return 0;
+}
diff --git a/tests/bionic/libc/other/test_aligned.c b/tests/bionic/libc/other/test_aligned.c
new file mode 100644
index 00000000..8a66dd65
--- /dev/null
+++ b/tests/bionic/libc/other/test_aligned.c
@@ -0,0 +1,117 @@
+#include <stdio.h>
+#include <arpa/inet.h> /* for htons() etc.. */
+
+static char tab[8];
+
+static void
+read4( int o, unsigned val )
+{
+ unsigned v = htonl(val);
+ unsigned v2;
+
+ tab[o+0] = (char)(v >> 24);
+ tab[o+1] = (char)(v >> 16);
+ tab[o+2] = (char)(v >> 8);
+ tab[o+3] = (char)(v);
+
+ printf( "read4: offset=%d value=%08x: ", o, val );
+ fflush(stdout);
+
+ v2 = *(unsigned*)(tab+o);
+
+ if (v2 != val) {
+ printf( "FAIL (%08x)\n", v2 );
+ } else {
+ printf( "ok\n" );
+ }
+}
+
+static void
+writ4( int o, unsigned val )
+{
+ unsigned v = htonl(val);
+ unsigned v2;
+
+ printf( "writ4: offset=%d value=%08x: ", o, val );
+ fflush(stdout);
+
+ *(unsigned*)(tab+o) = v;
+
+ v2 = ((unsigned)tab[o+0] << 24) |
+ ((unsigned)tab[o+1] << 16) |
+ ((unsigned)tab[o+2] << 8 ) |
+ ((unsigned)tab[o+3] );
+
+ if (v2 != val) {
+ printf( "FAIL (%08x)\n", v2 );
+ } else {
+ printf( "ok\n" );
+ }
+}
+
+static void
+read2( int o, unsigned val )
+{
+ unsigned short v = htons(val);
+ unsigned short v2;
+
+ tab[o+0] = (char)(v >> 8);
+ tab[o+1] = (char)(v);
+
+ printf( "read2: offset=%d value=%08x: ", o, val );
+ fflush(stdout);
+
+ v2 = *(unsigned short*)(tab+o);
+
+ if (v2 != val) {
+ printf( "FAIL (%04x)\n", v2 );
+ } else {
+ printf( "ok\n" );
+ }
+}
+
+static void
+writ2( int o, unsigned val )
+{
+ unsigned short v = htons(val);
+ unsigned short v2;
+
+ printf( "writ2: offset=%d value=%08x: ", o, val );
+ fflush(stdout);
+
+ *(unsigned short*)(tab+o) = v;
+
+ v2 = ((unsigned)tab[o+0] << 8) |
+ ((unsigned)tab[o+1] );
+
+ if (v2 != val) {
+ printf( "FAIL (%08x)\n", v2 );
+ } else {
+ printf( "ok\n" );
+ }
+}
+
+
+
+int main(void)
+{
+ read4( 0, 0x12345678 );
+ writ4( 0, 0x12345678 );
+ read4( 1, 0x12345678 );
+ writ4( 1, 0x12345678 );
+ read4( 2, 0x12345678 );
+ writ4( 2, 0x12345678 );
+ read4( 3, 0x12345678 );
+ writ4( 3, 0x12345678 );
+
+ read2( 0, 0x1234 );
+ writ2( 0, 0x1234 );
+ read2( 1, 0x1234 );
+ writ2( 1, 0x1234 );
+ read2( 2, 0x1234 );
+ writ2( 2, 0x1234 );
+ read2( 3, 0x1234 );
+ writ2( 3, 0x1234 );
+
+ return 0;
+}
diff --git a/tests/bionic/libc/other/test_arc4random.c b/tests/bionic/libc/other/test_arc4random.c
new file mode 100644
index 00000000..4829a2d6
--- /dev/null
+++ b/tests/bionic/libc/other/test_arc4random.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 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 <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ unsigned int arc4random();
+
+ int i;
+
+ for (i = 0; i < 50; i++) {
+ printf("%u\n", arc4random());
+ }
+ return 0;
+}
diff --git a/tests/bionic/libc/other/test_atomics.c b/tests/bionic/libc/other/test_atomics.c
new file mode 100644
index 00000000..0de2a938
--- /dev/null
+++ b/tests/bionic/libc/other/test_atomics.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+
+extern int __atomic_dec(volatile int* addr);
+
+int main(int argc, const char *argv[])
+{
+ int x = 5;
+
+ while (x > -20) {
+ printf("old_x=%d\n", __atomic_dec(&x));
+ printf("x=%d\n", x);
+ }
+
+ printf ("OK\n");
+ return 0;
+}
diff --git a/tests/bionic/libc/other/test_jpeg.c b/tests/bionic/libc/other/test_jpeg.c
new file mode 100644
index 00000000..f481b9a3
--- /dev/null
+++ b/tests/bionic/libc/other/test_jpeg.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+/* this small program is used to measure the performance of libjpeg decompression
+ * algorithm...
+ */
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include "jpeglib.h"
+#include <setjmp.h>
+#ifdef HAVE_ANDROID_OS
+#include <hardware_legacy/qemu_tracing.h>
+#endif
+
+#define USE_STDIO
+
+#define CHUNK 32768
+
+typedef struct {
+ struct jpeg_source_mgr jpeg_mgr;
+ char* base;
+ char* cursor;
+ char* end;
+} SourceMgrRec, *SourceMgr;
+
+static void
+_source_init_source(j_decompress_ptr cinfo)
+{
+ SourceMgr src = (SourceMgr) cinfo->src;
+
+ src->jpeg_mgr.next_input_byte = (unsigned char*)src->base,
+ src->jpeg_mgr.bytes_in_buffer = src->end - src->base;
+}
+
+static int
+_source_fill_input_buffer(j_decompress_ptr cinfo)
+{
+ SourceMgr src = (SourceMgr) cinfo->src;
+
+ cinfo->err->error_exit((j_common_ptr)cinfo);
+ return FALSE;
+}
+
+static void
+_source_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+ SourceMgr src = (SourceMgr) cinfo->src;
+
+ if (src->jpeg_mgr.next_input_byte + num_bytes > (unsigned char*)src->end ) {
+ cinfo->err->error_exit((j_common_ptr)cinfo);
+ }
+
+ src->jpeg_mgr.next_input_byte += num_bytes;
+ src->jpeg_mgr.bytes_in_buffer -= num_bytes;
+}
+
+static int
+_source_resync_to_restart( j_decompress_ptr cinfo, int desired)
+{
+ SourceMgr src = (SourceMgr) cinfo->src;
+
+ src->jpeg_mgr.next_input_byte = (unsigned char*)src->base;
+ src->jpeg_mgr.bytes_in_buffer = src->end - src->base;
+ return TRUE;
+}
+
+static void
+_source_term_source(j_decompress_ptr cinfo)
+{
+ // nothing to do
+}
+
+static void
+_source_init( SourceMgr src, char* base, long size )
+{
+ src->base = base;
+ src->cursor = base;
+ src->end = base + size;
+
+ src->jpeg_mgr.init_source = _source_init_source;
+ src->jpeg_mgr.fill_input_buffer = _source_fill_input_buffer;
+ src->jpeg_mgr.skip_input_data = _source_skip_input_data;
+ src->jpeg_mgr.resync_to_restart = _source_resync_to_restart;
+ src->jpeg_mgr.term_source = _source_term_source;
+}
+
+
+typedef struct {
+ struct jpeg_error_mgr jpeg_mgr;
+ jmp_buf jumper;
+ int volatile error;
+
+} ErrorMgrRec, *ErrorMgr;
+
+static void _error_exit(j_common_ptr cinfo)
+{
+ ErrorMgr error = (ErrorMgr) cinfo->err;
+
+ (*error->jpeg_mgr.output_message) (cinfo);
+
+ /* Let the memory manager delete any temp files before we die */
+ longjmp(error->jumper, -1);
+}
+
+#ifdef USE_STDIO
+int decompress(FILE* input_file, int dct_method, int disable_rgb)
+#else
+int decompress(char* data, long fsize)
+#endif
+{
+ ErrorMgrRec errmgr;
+ SourceMgrRec sourcemgr;
+ struct jpeg_decompress_struct cinfo;
+ int volatile error = 0;
+ jmp_buf jumper;
+ int isRGB;
+ char* pixels;
+ JSAMPLE* temprow;
+
+ memset( &cinfo, 0, sizeof(cinfo) );
+ memset( &errmgr, 0, sizeof(errmgr) );
+ jpeg_create_decompress(&cinfo);
+ cinfo.err = jpeg_std_error(&errmgr.jpeg_mgr);
+#if 0
+ errmgr.jpeg_mgr.error_exit = _error_exit;
+ errmgr.error = 0;
+#endif
+
+ if (setjmp(errmgr.jumper) != 0) {
+ fprintf(stderr, "returning error from jpeglib ---\n" );
+ goto Exit;
+ }
+
+#ifdef USE_STDIO
+ /* Specify data source for decompression */
+ jpeg_stdio_src(&cinfo, input_file);
+#else
+ _source_init( &sourcemgr, data, fsize );
+ cinfo.src = &sourcemgr.jpeg_mgr;
+#endif
+
+ jpeg_read_header(&cinfo, 1);
+
+ if (3 == cinfo.num_components && JCS_RGB == cinfo.out_color_space)
+ isRGB = 1;
+ else if (1 == cinfo.num_components && JCS_GRAYSCALE == cinfo.out_color_space)
+ isRGB = 0; // could use Index8 config if we want...
+ else {
+ fprintf( stderr, "unsupported jpeg colorspace %d with %d components\n",
+ cinfo.jpeg_color_space, cinfo.num_components );
+ goto Exit;
+ }
+
+ cinfo.dct_method = dct_method;
+ if (disable_rgb)
+ cinfo.out_color_space = JCS_YCbCr;
+
+ jpeg_start_decompress(&cinfo);
+
+ temprow = calloc( cinfo.num_components * cinfo.output_width, sizeof(JSAMPLE) );
+
+ {
+ unsigned y;
+ for (y = 0; y < cinfo.output_height; y++) {
+ JSAMPLE* rowptr = temprow;
+ (void)jpeg_read_scanlines(&cinfo, &rowptr, 1);
+ }
+ }
+ jpeg_finish_decompress(&cinfo);
+
+ free( temprow );
+Exit:
+ jpeg_destroy_decompress(&cinfo);
+ return error;
+}
+
+
+#define DEFAULT_REPEAT 10
+
+static void usage(void)
+{
+ fprintf(stderr, "usage: test_jpeg [options] filename.jpg [filename2.jpg ...]\n" );
+ fprintf(stderr, "options: -r NN repeat count (default %d)\n", DEFAULT_REPEAT );
+ fprintf(stderr, " -d N idct method (0=default, 1=fastest, 2=slow, 3=float)\n" );
+ fprintf(stderr, " -C no RGB color conversion (YCbCr instead)\n" );
+ exit(1);
+}
+
+static double
+get_time_usec( void )
+{
+#ifdef HAVE_ANDROID_OS
+ struct timespec ts;
+
+ if ( clock_gettime( CLOCK_MONOTONIC, &ts ) < 0 )
+ fprintf(stderr, "clock_gettime: %s\n", strerror(errno) );
+
+ return ts.tv_sec*1e6 + ts.tv_nsec*1e-3;
+#else
+ struct timeval tv;
+ if (gettimeofday( &tv, NULL ) < 0)
+ fprintf(stderr, "gettimeofday: %s\n", strerror(errno) );
+
+ return tv.tv_sec*1000000. + tv.tv_usec*1.0;
+#endif
+}
+
+
+int main( int argc, char** argv )
+{
+ FILE* f;
+ int repeat_count = DEFAULT_REPEAT;
+ int dct_method = JDCT_DEFAULT;
+ int disable_rgb = 0;
+ double usec0, usec1;
+
+ if (argc < 2)
+ usage();
+
+ for ( ; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
+ const char* arg = &argv[1][1];
+ switch (arg[0]) {
+ case 'r':
+ if (arg[1] == 0) {
+ if (argc < 3)
+ usage();
+ arg = argv[2];
+ argc--;
+ argv++;
+ } else
+ arg += 1;
+
+ repeat_count = strtol(arg, NULL, 10);
+
+ if (repeat_count <= 0)
+ repeat_count = 1;
+ break;
+
+ case 'C':
+ disable_rgb = 1;
+ break;
+
+ case 'd':
+ if (arg[1] == 0) {
+ if (argc < 3)
+ usage();
+ arg = argv[2];
+ argc--;
+ argv++;
+ } else
+ arg += 1;
+
+ dct_method = strtol(arg, NULL, 10);
+ switch (dct_method) {
+ case 0:
+ dct_method = JDCT_DEFAULT;
+ break;
+ case 1:
+ dct_method = JDCT_IFAST;
+ break;
+ case 2:
+ dct_method = JDCT_ISLOW;
+ break;
+ case 3:
+ dct_method = JDCT_FLOAT;
+ break;
+ default:
+ usage();
+ }
+ break;
+
+ default:
+ usage();
+ }
+ }
+
+ for ( ; argc > 1; argc--, argv++ )
+ {
+ long fsize;
+ char* data;
+ FILE* f = fopen( argv[1], "rb" );
+ int rr;
+
+ if (f == NULL) {
+ fprintf(stderr, "could not open '%s': %s\n", argv[1], strerror(errno) );
+ continue;
+ }
+
+ fseek( f, 0, SEEK_END );
+ fsize = ftell(f);
+ fseek( f, 0, SEEK_SET );
+
+ usec0 = get_time_usec();
+#ifdef HAVE_ANDROID_OS
+ qemu_start_tracing();
+#endif
+#ifdef USE_STDIO
+ for ( rr = repeat_count; rr > 0; rr-- ) {
+ fseek( f, 0, SEEK_SET );
+ decompress(f, dct_method, disable_rgb);
+ }
+ fclose( f );
+#else
+
+ data = malloc( fsize );
+ if (data == NULL) {
+ if (fsize > 0)
+ fprintf(stderr, "could not allocate %ld bytes to load '%s'\n", fsize, argv[1] );
+ fclose(f);
+ continue;
+ }
+ fread( data, 1, fsize, f );
+ fclose(f);
+
+ usec1 = get_time_usec() - usec0;
+ printf( "compressed load: %10.2f ms (%ld bytes)\n", usec1*1e-3, fsize );
+
+ usec0 = get_time_usec();
+ for ( rr = repeat_count; rr > 0; rr -- )
+ {
+ decompress( data, fsize );
+ }
+ free( data );
+#endif
+#ifdef HAVE_ANDROID_OS
+ qemu_stop_tracing();
+#endif
+ usec1 = get_time_usec() - usec0;
+ printf( "decompression took: %10.3f ms (%.2f KB/s, %d passes)\n", usec1/1e3, fsize*(1e6/1024)*repeat_count/usec1, repeat_count );
+ }
+ return 0;
+}
diff --git a/tests/bionic/libc/other/test_sysconf.c b/tests/bionic/libc/other/test_sysconf.c
new file mode 100644
index 00000000..717cbcb3
--- /dev/null
+++ b/tests/bionic/libc/other/test_sysconf.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008 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 <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#define T(_name,_cond) \
+ errno = 0; \
+ printf( "testing %-*s : ", 32, #_name ); \
+ ret = sysconf( _name ); \
+ if (ret < 0 && errno != 0) { \
+ printf( "error: %s\n", strerror(errno) ); \
+ } else { \
+ if ( ret _cond ) { \
+ printf( "OK (%d)\n", ret ); \
+ } else { \
+ printf( "ERROR: %d does not meet %s\n", ret, #_cond ); \
+ } \
+ }
+
+int main( void )
+{
+ int ret;
+ T(_SC_ARG_MAX, > 0);
+ T(_SC_BC_BASE_MAX, |1 );
+ T(_SC_BC_DIM_MAX, |1 );
+ T(_SC_BC_SCALE_MAX, |1 );
+ T(_SC_BC_STRING_MAX, |1 );
+ T(_SC_CHILD_MAX, >0 );
+ T(_SC_CLK_TCK, >0 );
+ T(_SC_COLL_WEIGHTS_MAX, |1 );
+ T(_SC_EXPR_NEST_MAX, |1 );
+ T(_SC_LINE_MAX, > 256 );
+ T(_SC_NGROUPS_MAX, >0 );
+ T(_SC_OPEN_MAX, >128 );
+ T(_SC_PASS_MAX, |1 );
+ T(_SC_2_C_BIND, >0 );
+ T(_SC_2_C_DEV, |1 );
+ T(_SC_2_C_VERSION, |1 );
+ T(_SC_2_CHAR_TERM, |1 );
+ T(_SC_2_FORT_DEV, |1 );
+ T(_SC_2_FORT_RUN, |1 );
+ T(_SC_2_LOCALEDEF, |1 );
+ T(_SC_2_SW_DEV, |1 );
+ T(_SC_2_UPE, |1 );
+ T(_SC_2_VERSION, |1);
+ T(_SC_JOB_CONTROL, == 1);
+ T(_SC_SAVED_IDS, == 1);
+ T(_SC_VERSION, |1);
+ T(_SC_RE_DUP_MAX, |1);
+ T(_SC_STREAM_MAX, > 0);
+ T(_SC_TZNAME_MAX, |1 );
+ T(_SC_XOPEN_CRYPT, |1 );
+ T(_SC_XOPEN_ENH_I18N, |1 );
+ T(_SC_XOPEN_SHM, |1 );
+ T(_SC_XOPEN_VERSION, |1 );
+ T(_SC_XOPEN_XCU_VERSION, |1 );
+ T(_SC_XOPEN_REALTIME, |1 );
+ T(_SC_XOPEN_REALTIME_THREADS, |1 );
+ T(_SC_XOPEN_LEGACY, |1 );
+ T(_SC_ATEXIT_MAX, >32 );
+ T(_SC_IOV_MAX, >0 );
+ T(_SC_PAGESIZE, == 4096 );
+ T(_SC_PAGE_SIZE, == 4096 );
+ T(_SC_XOPEN_UNIX, |1 );
+ T(_SC_XBS5_ILP32_OFF32, |1 );
+ T(_SC_XBS5_ILP32_OFFBIG, |1 );
+ T(_SC_XBS5_LP64_OFF64, |1 );
+ T(_SC_XBS5_LPBIG_OFFBIG, |1 );
+ T(_SC_AIO_LISTIO_MAX, |1 );
+ T(_SC_AIO_MAX, |1 );
+ T(_SC_AIO_PRIO_DELTA_MAX, |1 );
+ T(_SC_DELAYTIMER_MAX, >0 );
+ T(_SC_MQ_OPEN_MAX, |1 );
+ T(_SC_MQ_PRIO_MAX, >0 );
+ T(_SC_RTSIG_MAX, |1 );
+ T(_SC_SEM_NSEMS_MAX, |1 );
+ T(_SC_SEM_VALUE_MAX, |1 );
+ T(_SC_SIGQUEUE_MAX, >0 );
+ T(_SC_TIMER_MAX, |1 );
+ T(_SC_ASYNCHRONOUS_IO, |1 );
+ T(_SC_FSYNC, |1 );
+ T(_SC_MAPPED_FILES, |1 );
+ T(_SC_MEMLOCK, |1 );
+ T(_SC_MEMLOCK_RANGE, |1 );
+ T(_SC_MEMORY_PROTECTION, |1 );
+ T(_SC_MESSAGE_PASSING, |1 );
+ T(_SC_PRIORITIZED_IO, |1 );
+ T(_SC_PRIORITY_SCHEDULING, |1 );
+ T(_SC_REALTIME_SIGNALS, |1 );
+ T(_SC_SEMAPHORES, |1 );
+ T(_SC_SHARED_MEMORY_OBJECTS, |1 );
+ T(_SC_SYNCHRONIZED_IO, |1 );
+ T(_SC_TIMERS, |1 );
+ T(_SC_GETGR_R_SIZE_MAX, |1 );
+ T(_SC_GETPW_R_SIZE_MAX, |1 );
+ T(_SC_LOGIN_NAME_MAX, |1 );
+ T(_SC_THREAD_DESTRUCTOR_ITERATIONS, |1 );
+ T(_SC_THREAD_KEYS_MAX, > 0 );
+ T(_SC_THREAD_STACK_MIN, >= 8192 );
+ T(_SC_THREAD_THREADS_MAX, |1 );
+ T(_SC_TTY_NAME_MAX, > 0 );
+ T(_SC_THREADS, |1 );
+ T(_SC_THREAD_ATTR_STACKADDR, |1 );
+ T(_SC_THREAD_ATTR_STACKSIZE, |1 );
+ T(_SC_THREAD_PRIORITY_SCHEDULING, |1 );
+ T(_SC_THREAD_PRIO_INHERIT, |1 );
+ T(_SC_THREAD_PRIO_PROTECT, |1 );
+ T(_SC_THREAD_SAFE_FUNCTIONS, |1 );
+ return 0;
+}
diff --git a/tests/bionic/libc/other/test_system.c b/tests/bionic/libc/other/test_system.c
new file mode 100644
index 00000000..adb4c56a
--- /dev/null
+++ b/tests/bionic/libc/other/test_system.c
@@ -0,0 +1,28 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+int
+main(int argc, char *argv[])
+{
+ int rv;
+
+ if (argc < 2)
+ return -1;
+
+ rv = system(argv[1]);
+ if (rv < 0) {
+ fprintf(stderr, "Error calling system(): %d\n", errno);
+ return 1;
+ }
+
+ printf("Done!\n");
+
+ if (WEXITSTATUS(rv) != 0) {
+ fprintf(stderr, "Command returned non-zero exit code: %d\n",
+ WEXITSTATUS(rv));
+ return 1;
+ }
+ return 0;
+}
diff --git a/tests/bionic/libc/other/test_thread_max.c b/tests/bionic/libc/other/test_thread_max.c
new file mode 100644
index 00000000..7aeb5c5a
--- /dev/null
+++ b/tests/bionic/libc/other/test_thread_max.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 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 <pthread.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+
+static void*
+thread_func( void* arg )
+{
+ fprintf(stderr, "thread %ld\n", (long)arg );
+ return NULL;
+}
+
+int main( void )
+{
+ int count;
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
+ pthread_attr_setstacksize( &attr, 16*4096 );
+
+ for ( count = 0; count != ~0; count++ ) {
+ pthread_t thread;
+ struct timespec ts;
+
+ if (pthread_create( &thread, &attr, thread_func, (void*)(long)count ) < 0) {
+ fprintf(stderr, "could not create thread %d\n", count);
+ break;
+ }
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0.002*1e9;
+ nanosleep( &ts, &ts );
+ }
+ sleep(1);
+ return 0;
+}
diff --git a/tests/bionic/libc/other/test_timer_create.c b/tests/bionic/libc/other/test_timer_create.c
new file mode 100644
index 00000000..8995e121
--- /dev/null
+++ b/tests/bionic/libc/other/test_timer_create.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008 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 <stdio.h>
+#include <time.h>
+#include <signal.h>
+#include <pthread.h>
+#include <string.h>
+#include <unistd.h>
+
+void
+handle(sigval_t v)
+{
+ time_t t;
+ char p[32];
+
+ time(&t);
+ strftime(p, sizeof(p), "%T", localtime(&t));
+ printf("%s thread %d, val = %d, signal captured.\n",
+ p, (int)pthread_self(), v.sival_int);
+ return;
+}
+
+int
+create(int seconds, int id)
+{
+ timer_t tid;
+ struct sigevent se;
+ struct itimerspec ts, ots;
+
+ memset(&se, 0, sizeof (se));
+ se.sigev_notify = SIGEV_THREAD;
+ se.sigev_notify_function = handle;
+ se.sigev_value.sival_int = id;
+
+ if (timer_create (CLOCK_REALTIME, &se, &tid) < 0)
+ {
+ perror ("timer_creat");
+ return -1;
+ }
+ puts ("timer_create successfully.");
+ ts.it_value.tv_sec = 3;
+ ts.it_value.tv_nsec = 0;
+ ts.it_interval.tv_sec = seconds;
+ ts.it_interval.tv_nsec = 0;
+ if (timer_settime (tid, TIMER_ABSTIME, &ts, &ots) < 0)
+ {
+ perror ("timer_settime");
+ return -1;
+ }
+ return 0;
+}
+
+int
+main (void)
+{
+ if (create (3, 1) < 0) return 1;
+ if (create (5, 2) < 0) return 1;
+ for (;;)
+ {
+ sleep (10);
+ }
+ return 0;
+}
diff --git a/tests/bionic/libc/other/test_timer_create2.c b/tests/bionic/libc/other/test_timer_create2.c
new file mode 100644
index 00000000..10e95e4e
--- /dev/null
+++ b/tests/bionic/libc/other/test_timer_create2.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2008 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 <stdio.h>
+#include <time.h>
+#include <signal.h>
+#include <pthread.h>
+#include <string.h>
+#include <unistd.h>
+
+void
+handle(int v)
+{
+ time_t t;
+ char p[32];
+
+ time(&t);
+ strftime(p, sizeof(p), "%T", localtime(&t));
+ printf("%s thread %p, val = %d, signal captured.\n",
+ p, pthread_self(), v);
+ return;
+}
+
+int
+create(int seconds, int id)
+{
+ timer_t tid;
+ struct sigevent se;
+ struct itimerspec ts, ots;
+
+ memset(&se, 0, sizeof (se));
+ se.sigev_notify = SIGEV_SIGNAL;
+ se.sigev_signo = SIGUSR1;
+
+ if (timer_create (CLOCK_REALTIME, &se, &tid) < 0)
+ {
+ perror ("timer_creat");
+ return -1;
+ }
+ printf("timer_create successfully = %d.\n", (int)tid);
+ ts.it_value.tv_sec = 3;
+ ts.it_value.tv_nsec = 0;
+ ts.it_interval.tv_sec = seconds;
+ ts.it_interval.tv_nsec = 0;
+ if (timer_settime (tid, TIMER_ABSTIME, &ts, &ots) < 0)
+ {
+ perror ("timer_settime");
+ return -1;
+ }
+ return 0;
+}
+
+int
+main (void)
+{
+ sigset_t mask[1];
+ struct sigaction act[1];
+
+ sigemptyset(mask);
+ sigaddset(mask, SIGUSR1);
+ sigprocmask(SIG_UNBLOCK,mask,NULL);
+
+ memset(act, 0, sizeof(*act));
+ act->sa_handler = handle;
+ sigaction( SIGUSR1, act, NULL );
+
+ printf("main thread is %p\n", pthread_self());
+
+ if (create (3, 1) < 0) return 1;
+ if (create (5, 2) < 0) return 1;
+ for (;;)
+ {
+ sleep (10);
+ }
+ return 0;
+}
diff --git a/tests/bionic/libc/other/test_timer_create3.c b/tests/bionic/libc/other/test_timer_create3.c
new file mode 100644
index 00000000..193f37ef
--- /dev/null
+++ b/tests/bionic/libc/other/test_timer_create3.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 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 <stdio.h>
+#include <time.h>
+#include <signal.h>
+#include <pthread.h>
+#include <string.h>
+#include <unistd.h>
+
+static timer_t tid;
+static int count;
+
+/* this test program is there to check that disarming a timer
+ * can be done by calling timer_settime() with an it_interval
+ * value of 0
+ */
+void
+handle(sigval_t v)
+{
+ time_t t;
+ char p[32];
+ struct itimerspec ts;
+
+ time(&t);
+ strftime(p, sizeof(p), "%T", localtime(&t));
+ printf("%s thread %d, val = %d, signal captured.\n",
+ p, (int)pthread_self(), v.sival_int);
+ count += 1;
+
+ /* this should disable the timer, and hence make 'count' no more than 1 */
+ ts.it_value.tv_sec = 0;
+ ts.it_value.tv_nsec = 0;
+ ts.it_interval.tv_sec = 1;
+ ts.it_interval.tv_nsec = 0;
+ timer_settime(tid, TIMER_ABSTIME, &ts, NULL);
+
+ return;
+}
+
+int
+create(int seconds, int id)
+{
+ struct sigevent se;
+ struct itimerspec ts, ots;
+
+ memset(&se, 0, sizeof (se));
+ se.sigev_notify = SIGEV_THREAD;
+ se.sigev_notify_function = handle;
+ se.sigev_value.sival_int = id;
+
+ if (timer_create (CLOCK_REALTIME, &se, &tid) < 0)
+ {
+ perror ("timer_creat");
+ return -1;
+ }
+ puts ("timer_create successfully.");
+ ts.it_value.tv_sec = 0;
+ ts.it_value.tv_nsec = 1;
+ ts.it_interval.tv_sec = seconds;
+ ts.it_interval.tv_nsec = 0;
+ if (timer_settime (tid, TIMER_ABSTIME, &ts, &ots) < 0)
+ {
+ perror ("timer_settime");
+ return -1;
+ }
+ return 0;
+}
+
+int
+main (void)
+{
+ if (create (1, 1) < 0) return 1;
+ sleep (4);
+
+ if (count == 1) {
+ printf("OK\n");
+ return 0;
+ } else {
+ printf("KO (count=%d)\n", count);
+ return 1;
+ }
+}
diff --git a/tests/bionic/libc/other/test_vfprintf_leak.c b/tests/bionic/libc/other/test_vfprintf_leak.c
new file mode 100644
index 00000000..4e94c51b
--- /dev/null
+++ b/tests/bionic/libc/other/test_vfprintf_leak.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+/* this test is used to check that a memory-leak in vfprintf was fixed.
+ * the initial code leaked heap memory each time a formatted double was printed
+ */
+#include <stdio.h>
+
+extern size_t dlmalloc_footprint();
+
+int main(void)
+{
+ size_t initial = dlmalloc_footprint();
+ size_t final;
+ char temp[64];
+ int n;
+
+ for (n = 0; n < 10000; n++)
+ snprintf( temp, sizeof(temp), "%g", n*0.647287623 );
+
+ final = dlmalloc_footprint();
+ /* vfprintf uses temporary heap blocks to do the formatting, so */
+ /* it's OK to have one page in there */
+ if (final <= 4096) {
+ printf( "OK: initial = %ld, final == %ld\n", (long)initial, (long)final );
+ return 0;
+ } else {
+ fprintf(stderr, "KO: initial == %ld, final == %ld\n", (long)initial, (long)final );
+ return 1;
+ }
+}
diff --git a/tests/bionic/libc/other/test_zlib.c b/tests/bionic/libc/other/test_zlib.c
new file mode 100644
index 00000000..3eae8279
--- /dev/null
+++ b/tests/bionic/libc/other/test_zlib.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+/* this small program is used to measure the performance of zlib's inflate
+ * algorithm...
+ */
+
+/* most code lifted from the public-domain http://www.zlib.net/zpipe.c */
+
+#include <zlib.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#define CHUNK 32768
+
+int def(FILE *source, FILE *dest, int level)
+{
+ int ret, flush;
+ unsigned have;
+ z_stream strm;
+ unsigned char in[CHUNK];
+ unsigned char out[CHUNK];
+
+ /* allocate deflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ ret = deflateInit(&strm, level);
+ if (ret != Z_OK)
+ return ret;
+
+ /* compress until end of file */
+ do {
+ strm.avail_in = fread(in, 1, CHUNK, source);
+ if (ferror(source)) {
+ (void)deflateEnd(&strm);
+ return Z_ERRNO;
+ }
+ flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
+ strm.next_in = in;
+
+ /* run deflate() on input until output buffer not full, finish
+ compression if all of source has been read in */
+ do {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+ ret = deflate(&strm, flush); /* no bad return value */
+ have = CHUNK - strm.avail_out;
+ if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
+ (void)deflateEnd(&strm);
+ return Z_ERRNO;
+ }
+ } while (strm.avail_out == 0);
+
+ /* done when last data in file processed */
+ } while (flush != Z_FINISH);
+
+ /* clean up and return */
+ (void)deflateEnd(&strm);
+ return Z_OK;
+}
+
+
+int inf(FILE *source)
+{
+ int ret;
+ unsigned have;
+ z_stream strm;
+ static unsigned char in[CHUNK];
+ static unsigned char out[CHUNK];
+
+ /* allocate inflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit(&strm);
+ if (ret != Z_OK)
+ return ret;
+
+ /* decompress until deflate stream ends or end of file */
+ do {
+ strm.avail_in = fread(in, 1, CHUNK, source);
+ if (ferror(source)) {
+ (void)inflateEnd(&strm);
+ return Z_ERRNO;
+ }
+ if (strm.avail_in == 0)
+ break;
+ strm.next_in = in;
+
+ /* run inflate() on input until output buffer not full */
+ do {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+ ret = inflate(&strm, Z_NO_FLUSH);
+ switch (ret) {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR; /* and fall through */
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ (void)inflateEnd(&strm);
+ return ret;
+ }
+ } while (strm.avail_out == 0);
+
+ /* done when inflate() says it's done */
+ } while (ret != Z_STREAM_END);
+
+ /* clean up and return */
+ (void)inflateEnd(&strm);
+ return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
+}
+
+#define DEFAULT_REPEAT 10
+#define DEFAULT_LEVEL 9
+
+static void usage(void)
+{
+ fprintf(stderr, "usage: test_zlib [options] filename [filename2 ...]\n" );
+ fprintf(stderr, "options: -r NN repeat count (default %d)\n", DEFAULT_REPEAT );
+ fprintf(stderr, " -N set compression level (default %d)\n", DEFAULT_LEVEL );
+ exit(1);
+}
+
+static double
+get_time_usec( void )
+{
+#ifdef HAVE_ANDROID_OS
+ struct timespec ts;
+
+ if ( clock_gettime( CLOCK_MONOTONIC, &ts ) < 0 )
+ fprintf(stderr, "clock_gettime: %s\n", strerror(errno) );
+
+ return ts.tv_sec*1e6 + ts.tv_nsec*1e-3;
+#else
+ struct timeval tv;
+ if (gettimeofday( &tv, NULL ) < 0)
+ fprintf(stderr, "gettimeofday: %s\n", strerror(errno) );
+
+ return tv.tv_sec*1000000. + tv.tv_usec*1.0;
+#endif
+}
+
+int main( int argc, char** argv )
+{
+ FILE* f;
+ char tempfile[256];
+ int repeat_count = DEFAULT_REPEAT;
+ int compression_level = DEFAULT_LEVEL;
+ double usec0, usec1;
+
+ if (argc < 2)
+ usage();
+
+ for ( ; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
+ const char* arg = &argv[1][1];
+ switch (arg[0]) {
+ case 'r':
+ if (arg[1] == 0) {
+ if (argc < 3)
+ usage();
+ arg = argv[2];
+ argc--;
+ argv++;
+ } else
+ arg += 1;
+
+ repeat_count = strtol(arg, NULL, 10);
+
+ if (repeat_count <= 0)
+ repeat_count = 1;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ compression_level = arg[0] - '0';
+ break;
+
+ default:
+ usage();
+ }
+ }
+
+ sprintf(tempfile, "/tmp/ztest.%d", getpid() );
+
+ for ( ; argc > 1; argc--, argv++ )
+ {
+ /* first, compress the file into a temporary storage */
+ FILE* f = fopen(argv[1], "rb");
+ FILE* out = NULL;
+ long fsize;
+ int ret, rr;
+
+ if (f == NULL) {
+ fprintf(stderr, "could not open '%s': %s\n", argv[1], strerror(errno) );
+ continue;
+ }
+
+ printf( "testing %s\n", argv[1] );
+ fseek( f, 0, SEEK_END );
+ fsize = ftell(f);
+ fseek( f, 0, SEEK_SET );
+
+ out = fopen( tempfile, "wb" );
+ if (out == NULL) {
+ fprintf(stderr, "could not create '%s': %s\n", tempfile, strerror(errno));
+ fclose(f);
+ continue;
+ }
+
+ usec0 = get_time_usec();
+
+ ret = def( f, out, compression_level );
+
+ usec1 = get_time_usec() - usec0;
+ printf( "compression took: %10.3f ms (%.2f KB/s)\n", usec1/1e3, fsize*(1e6/1024)/usec1 );
+
+ fclose( out );
+ fclose(f);
+
+ usec0 = get_time_usec();
+ f = fopen( tempfile, "rb" );
+
+ for ( rr = repeat_count; rr > 0; rr -- )
+ {
+ fseek( f, 0, SEEK_SET );
+ inf(f);
+ }
+ fclose( f );
+ usec1 = get_time_usec() - usec0;
+ printf( "decompression took: %10.3f ms (%.2f KB/s, %d passes)\n", usec1/1e3, fsize*(1e6/1024)*repeat_count/usec1, repeat_count );
+ }
+
+ unlink(tempfile);
+ return 0;
+}
diff --git a/tests/cpueater/Android.mk b/tests/cpueater/Android.mk
new file mode 100644
index 00000000..29a524e1
--- /dev/null
+++ b/tests/cpueater/Android.mk
@@ -0,0 +1,32 @@
+# 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 := tests eng
+LOCAL_SRC_FILES := cpueater.c
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := daemonize
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := tests eng
+LOCAL_SRC_FILES := daemonize.c
+LOCAL_SHARED_LIBRARIES := libhardware_legacy
+include $(BUILD_EXECUTABLE)
+
diff --git a/tests/cpueater/cpueater.c b/tests/cpueater/cpueater.c
new file mode 100644
index 00000000..c7911392
--- /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 00000000..3839cdcf
--- /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"
+
+
+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/framebuffer/Android.mk b/tests/framebuffer/Android.mk
new file mode 100644
index 00000000..d6a8537d
--- /dev/null
+++ b/tests/framebuffer/Android.mk
@@ -0,0 +1,33 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ refresh.c
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils
+
+LOCAL_MODULE:= test-fb-refresh
+
+LOCAL_MODULE_TAGS := tests
+
+ifeq ($(TARGET_SIMULATOR),true)
+ ifeq ($(HOST_OS),linux)
+ # need this for clock_gettime()
+ LOCAL_LDLIBS += -lrt
+ endif
+endif
+
+include $(BUILD_EXECUTABLE)
+
+##
+
+ifneq ($(TARGET_SIMULATOR),true)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := fb_test.c
+LOCAL_MODULE = test-fb-simple
+LOCAL_MODULE_TAGS := tests
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := libc
+include $(BUILD_EXECUTABLE)
+endif # sim
diff --git a/tests/framebuffer/fb_test.c b/tests/framebuffer/fb_test.c
new file mode 100644
index 00000000..6fdbf3b3
--- /dev/null
+++ b/tests/framebuffer/fb_test.c
@@ -0,0 +1,232 @@
+/*
+ * 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>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "minui.h"
+
+typedef struct {
+ GGLSurface texture;
+ unsigned cwidth;
+ unsigned cheight;
+ unsigned ascent;
+} GRFont;
+
+static GGLContext *gr_context = 0;
+static GGLSurface gr_framebuffer[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(GGLSurface *fb)
+{
+ int fd;
+ void *bits;
+
+ fd = open("/dev/graphics/fb0", O_RDWR);
+ if(fd < 0) {
+ perror("cannot open fb0");
+ return -1;
+ }
+
+ if(ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
+ perror("failed to get fb0 info");
+ return -1;
+ }
+
+ if(ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 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;
+ }
+
+ fb->version = sizeof(*fb);
+ fb->width = vi.xres;
+ fb->height = vi.yres;
+ fb->stride = fi.line_length / (vi.bits_per_pixel >> 3);
+ fb->data = bits;
+ fb->format = GGL_PIXEL_FORMAT_RGB_565;
+
+ fb++;
+
+ fb->version = sizeof(*fb);
+ fb->width = vi.xres;
+ fb->height = vi.yres;
+ fb->stride = fi.line_length / (vi.bits_per_pixel >> 3);
+ fb->data = (void*) (((unsigned) bits) + vi.yres * vi.xres * 2);
+ fb->format = GGL_PIXEL_FORMAT_RGB_565;
+
+ 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");
+ }
+}
+
+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(void)
+{
+ int fd;
+
+
+ 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_framebuffer);
+
+ if(gr_fb_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 = 0;
+ set_active_framebuffer(0);
+
+ return 0;
+}
+
+void gr_exit(void)
+{
+ close(gr_fb_fd);
+ gr_fb_fd = -1;
+
+ ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT);
+ close(gr_vt_fd);
+ gr_vt_fd = -1;
+}
+
+int gr_fb_width(void)
+{
+ return gr_framebuffer[0].width;
+}
+
+int gr_fb_height(void)
+{
+ return gr_framebuffer[0].height;
+}
+
+uint16_t red = 0xf800;
+uint16_t green = 0x07e0;
+uint16_t blue = 0x001f;
+
+void draw_grid(int w, int h, uint16_t* loc) {
+ int i, j;
+ int v;
+ int stride = fi.line_length / (vi.bits_per_pixel >> 3);
+
+ for (j = 0; j < h/2; j++) {
+ for (i = 0; i < w/2; i++)
+ loc[i + j*(stride)] = red;
+ for (; i < w; i++)
+ loc[i + j*(stride)] = green;
+ }
+ for (; j < h; j++) {
+ for (i = 0; i < w/2; i++)
+ loc[i + j*(stride)] = blue;
+ for (; i < w; i++)
+ loc[i + j*(stride)] = 0xffff;
+ }
+
+}
+
+void clear_screen(int w, int h, uint16_t* loc)
+{
+ int i,j;
+ int stride = fi.line_length / (vi.bits_per_pixel >> 3);
+
+ for (j = 0; j < h; j++)
+ for (i = 0; i < w; i++)
+ loc[i + j*(stride)] = 0x0000;
+}
+
+
+int main(int argc, char **argv) {
+ int w;
+ int h;
+ gr_init();
+ w = vi.xres;
+ h = vi.yres;
+ clear_screen(w, h, (uint16_t *)gr_framebuffer[0].data);
+
+ if (argc > 2) {
+ w = atoi(argv[1]);
+ h = atoi(argv[2]);
+ }
+
+ draw_grid(w, h, (uint16_t *)gr_framebuffer[0].data);
+ printf("%lld\n", (tv2.tv_sec*1000000000LL + tv2.tv_nsec) - (tv.tv_sec*1000000000LL + tv.tv_nsec));
+ set_active_framebuffer(1);
+ set_active_framebuffer(0);
+
+ return 0;
+}
diff --git a/tests/framebuffer/minui.h b/tests/framebuffer/minui.h
new file mode 100644
index 00000000..4efc9719
--- /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 00000000..43dc7cff
--- /dev/null
+++ b/tests/framebuffer/refresh.c
@@ -0,0 +1,169 @@
+#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;
+
+ int refreshRate = 1000000000000000LLU /
+ (
+ (uint64_t)( info.upper_margin + info.lower_margin + info.yres )
+ * ( info.left_margin + info.right_margin + info.xres )
+ * info.pixclock
+ );
+
+ 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 00000000..bf4f17c3
--- /dev/null
+++ b/tests/fstest/Android.mk
@@ -0,0 +1,43 @@
+# 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_SRC_FILES := perm_checker.c
+
+LOCAL_SHARED_LIBRARIES := libc
+
+LOCAL_MODULE := perm_checker
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
+
+####
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := perm_checker.conf
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MODULE_CLASS := ETC
+
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/tests/fstest/README b/tests/fstest/README
new file mode 100644
index 00000000..e4f8194c
--- /dev/null
+++ b/tests/fstest/README
@@ -0,0 +1,68 @@
+All files and directories will be matched against entries taken from
+/etc/perm_checker.conf, and any file/directory which fails the ruleset
+will cause an error message along with a corresponding explicit (fully
+specified and minimal) rule for that file/directory to be printed on
+stdout. If only the message "Passed." is printed on stdout, all files are
+correctly matched by perm_checker.conf.
+
+A file or directory will always fail the ruleset unless there is AT LEAST
+one matching rule. If there is an explicit (fully specified) <spec>
+matching the file or directory name, it will fail if and only if that
+explicit <spec> rule fails (i.e., other matching <spec> rules will be
+ignored). Otherwise, it will fail if _any_ matching wildcard or recursive
+<spec> rule fails to hold.
+
+Entries in the perm_checker.conf file are of the following form:
+
+<spec> <min_mode> <max_mode> <min_uid> <max_uid> <min_gid> <max_gid>
+
+Where <spec> is one of the following:
+
+A fully specified path name, which must end in / ex: /dev/
+A fully specified filename, symlink, device node, etc. ex: /dev/tty0
+
+A recursive path specification, which ends in /... ex: /dev/...
+A wildcard file specification, which ends in * ex: /dev/tty*
+
+By convention /dev/* will include all files directly in /dev/, but not files
+that are in subdirectories of /dev/, such as /dev/input/, unlike a
+recursive path specification. The wildcard notation * will never result in
+a match to a directory name.
+
+NOTE: Symbolic links are treated specially to prevent infinite recursion
+and simplify the ruleset. Symbolic links are ignored unless an explicit
+rule with the same name as the symlink exists, in which case the permissions
+on the rule must match the permissions on the symlink itself, not the target.
+
+<min_mode> is a numeric mode mask, and a mode will match it if and only if
+(min_mode & mode) == min_mode.
+
+<max_mode> is a numeric mode mask, and a mode will match it if and only if
+(max_mode | mode) == max_mode.
+
+<min_uid> may be either a numeric user id, or a user name (which must not
+start with a number). If it is a user name, getpwnam() will be used to
+translate it to a numeric user id.
+
+<max_uid>, <min_gid>, and <max_gid> have similar syntax to <min_uid>.
+
+
+-- Tips --
+
+I recommend to use 19999 as the maximum uid/gid whenever any valid
+application uid/gid is acceptable.
+
+Once the test is installed, it can be executed via:
+
+adb shell perm_checker
+
+To get a list of all failing rules:
+
+adb shell perm_checker | grep "^# INFO #" | sort | uniq
+
+To get a fully specified set of rules for all failing files:
+
+adb shell perm_checker | grep -v "^#"
+
+NOTE: There may be failing files even if no rules have failed, since a
+file that does not match any rule is a failure.
diff --git a/tests/fstest/perm_checker.c b/tests/fstest/perm_checker.c
new file mode 100644
index 00000000..86d2cdce
--- /dev/null
+++ b/tests/fstest/perm_checker.c
@@ -0,0 +1,399 @@
+/*
+ * 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.
+ */
+
+// A simple file permissions checker. See associated README.
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <pwd.h>
+#include <grp.h>
+
+#include <linux/kdev_t.h>
+
+#define PERMS(M) (M & ~S_IFMT)
+#define MAX_NAME_LEN 4096
+#define MAX_UID_LEN 256
+#define MAX_GID_LEN MAX_UID_LEN
+
+enum perm_rule_type {EXACT_FILE = 0, EXACT_DIR, WILDCARD, RECURSIVE,
+ NUM_PR_TYPES};
+
+struct perm_rule {
+ char *rule_text;
+ int rule_line;
+ char *spec;
+ mode_t min_mode;
+ mode_t max_mode;
+ uid_t min_uid;
+ uid_t max_uid;
+ gid_t min_gid;
+ gid_t max_gid;
+ enum perm_rule_type type;
+ struct perm_rule *next;
+};
+
+typedef struct perm_rule perm_rule_t;
+
+static perm_rule_t *rules[NUM_PR_TYPES];
+
+static uid_t str2uid(char *str, int line_num)
+{
+ struct passwd *pw;
+
+ if (isdigit(str[0]))
+ return (uid_t) atol(str);
+
+ if (!(pw = getpwnam(str))) {
+ printf("# ERROR # Invalid uid '%s' reading line %d\n", str, line_num);
+ exit(255);
+ }
+ return pw->pw_uid;
+}
+
+static gid_t str2gid(char *str, int line_num)
+{
+ struct group *gr;
+
+ if (isdigit(str[0]))
+ return (uid_t) atol(str);
+
+ if (!(gr = getgrnam(str))) {
+ printf("# ERROR # Invalid gid '%s' reading line %d\n", str, line_num);
+ exit(255);
+ }
+ return gr->gr_gid;
+}
+
+static int read_rules(FILE *fp)
+{
+ char spec[MAX_NAME_LEN + 5]; // Allows for "/..." suffix + terminator
+ char min_uid_buf[MAX_UID_LEN + 1], max_uid_buf[MAX_UID_LEN + 1];
+ char min_gid_buf[MAX_GID_LEN + 1], max_gid_buf[MAX_GID_LEN + 1];
+ char rule_text_buf[MAX_NAME_LEN + 2*MAX_UID_LEN + 2*MAX_GID_LEN + 9];
+ unsigned long min_mode, max_mode;
+ perm_rule_t *pr;
+ int res;
+ int num_rules = 0, num_lines = 0;
+
+ // Note: Use of an unsafe C function here is OK, since this is a test
+ while ((res = fscanf(fp, "%s %lo %lo %s %s %s %s\n", spec,
+ &min_mode, &max_mode, min_uid_buf, max_uid_buf,
+ min_gid_buf, max_gid_buf)) != EOF) {
+ num_lines++;
+ if (res < 7) {
+ printf("# WARNING # Invalid rule on line number %d\n", num_lines);
+ continue;
+ }
+ if (!(pr = malloc(sizeof(perm_rule_t)))) {
+ printf("Out of memory.\n");
+ exit(255);
+ }
+ if (snprintf(rule_text_buf, sizeof(rule_text_buf),
+ "%s %lo %lo %s %s %s %s", spec, min_mode, max_mode,
+ min_uid_buf, max_uid_buf, min_gid_buf, max_gid_buf)
+ >= (long int) sizeof(rule_text_buf)) {
+ // This should never happen, but just in case...
+ printf("# ERROR # Maximum length limits exceeded on line %d\n",
+ num_lines);
+ exit(255);
+ }
+ pr->rule_text = strndup(rule_text_buf, sizeof(rule_text_buf));
+ pr->rule_line = num_lines;
+ if (strstr(spec, "/...")) {
+ pr->spec = strndup(spec, strlen(spec) - 3);
+ pr->type = RECURSIVE;
+ } else if (spec[strlen(spec) - 1] == '*') {
+ pr->spec = strndup(spec, strlen(spec) - 1);
+ pr->type = WILDCARD;
+ } else if (spec[strlen(spec) - 1] == '/') {
+ pr->spec = strdup(spec);
+ pr->type = EXACT_DIR;
+ } else {
+ pr->spec = strdup(spec);
+ pr->type = EXACT_FILE;
+ }
+ if ((pr->spec == NULL) || (pr->rule_text == NULL)) {
+ printf("Out of memory.\n");
+ exit(255);
+ }
+ pr->min_mode = min_mode;
+ pr->max_mode = max_mode;
+ pr->min_uid = str2uid(min_uid_buf, num_lines);
+ pr->max_uid = str2uid(max_uid_buf, num_lines);
+ pr->min_gid = str2gid(min_gid_buf, num_lines);
+ pr->max_gid = str2gid(max_gid_buf, num_lines);
+
+ // Add the rule to the appropriate set
+ pr->next = rules[pr->type];
+ rules[pr->type] = pr;
+ num_rules++;
+#if 0 // Useful for debugging
+ printf("rule #%d: type = %d spec = %s min_mode = %o max_mode = %o "
+ "min_uid = %d max_uid = %d min_gid = %d max_gid = %d\n",
+ num_rules, pr->type, pr->spec, pr->min_mode, pr->max_mode,
+ pr->min_uid, pr->max_uid, pr->min_gid, pr->max_gid);
+#endif
+ }
+ return num_lines - num_rules;
+}
+
+static void print_failed_rule(const perm_rule_t *pr)
+{
+ printf("# INFO # Failed rule #%d: %s\n", pr->rule_line, pr->rule_text);
+}
+
+static void print_new_rule(const char *name, mode_t mode, uid_t uid, gid_t gid)
+{
+ struct passwd *pw;
+ struct group *gr;
+ gr = getgrgid(gid);
+ pw = getpwuid(uid);
+ printf("%s %4o %4o %s %d %s %d\n", name, mode, mode, pw->pw_name, uid,
+ gr->gr_name, gid);
+}
+
+// Returns 1 if the rule passes, prints the failure and returns 0 if not
+static int pass_rule(const perm_rule_t *pr, mode_t mode, uid_t uid, gid_t gid)
+{
+ if (((pr->min_mode & mode) == pr->min_mode) &&
+ ((pr->max_mode | mode) == pr->max_mode) &&
+ (pr->min_gid <= gid) && (pr->max_gid >= gid) &&
+ (pr->min_uid <= uid) && (pr->max_uid >= uid))
+ return 1;
+ print_failed_rule(pr);
+ return 0;
+}
+
+// Returns 0 on success
+static int validate_file(const char *name, mode_t mode, uid_t uid, gid_t gid)
+{
+ perm_rule_t *pr;
+ int rules_matched = 0;
+ int retval = 0;
+
+ pr = rules[EXACT_FILE];
+ while (pr != NULL) {
+ if (strcmp(name, pr->spec) == 0) {
+ if (!pass_rule(pr, mode, uid, gid))
+ retval++;
+ else
+ rules_matched++; // Exact match found
+ }
+ pr = pr->next;
+ }
+
+ if ((retval + rules_matched) > 1)
+ printf("# WARNING # Multiple exact rules for file: %s\n", name);
+
+ // If any exact rule matched or failed, we are done with this file
+ if (retval)
+ print_new_rule(name, mode, uid, gid);
+ if (rules_matched || retval)
+ return retval;
+
+ pr = rules[WILDCARD];
+ while (pr != NULL) {
+ // Check if the spec is a prefix of the filename, and that the file
+ // is actually in the same directory as the wildcard.
+ if ((strstr(name, pr->spec) == name) &&
+ (!strchr(name + strlen(pr->spec), '/'))) {
+ if (!pass_rule(pr, mode, uid, gid))
+ retval++;
+ else
+ rules_matched++;
+ }
+ pr = pr->next;
+ }
+
+ pr = rules[RECURSIVE];
+ while (pr != NULL) {
+ if (strstr(name, pr->spec) == name) {
+ if (!pass_rule(pr, mode, uid, gid))
+ retval++;
+ else
+ rules_matched++;
+ }
+ pr = pr->next;
+ }
+
+ if (!rules_matched)
+ retval++; // In case no rules either matched or failed, be sure to fail
+
+ if (retval)
+ print_new_rule(name, mode, uid, gid);
+
+ return retval;
+}
+
+// Returns 0 on success
+static int validate_link(const char *name, mode_t mode, uid_t uid, gid_t gid)
+{
+ perm_rule_t *pr;
+ int rules_matched = 0;
+ int retval = 0;
+
+ // For now, we match links against "exact" file rules only
+ pr = rules[EXACT_FILE];
+ while (pr != NULL) {
+ if (strcmp(name, pr->spec) == 0) {
+ if (!pass_rule(pr, mode, uid, gid))
+ retval++;
+ else
+ rules_matched++; // Exact match found
+ }
+ pr = pr->next;
+ }
+
+ if ((retval + rules_matched) > 1)
+ printf("# WARNING # Multiple exact rules for link: %s\n", name);
+ if (retval)
+ print_new_rule(name, mode, uid, gid);
+
+ // Note: Unlike files, if no rules matches for links, retval = 0 (success).
+ return retval;
+}
+
+// Returns 0 on success
+static int validate_dir(const char *name, mode_t mode, uid_t uid, gid_t gid)
+{
+ perm_rule_t *pr;
+ int rules_matched = 0;
+ int retval = 0;
+
+ pr = rules[EXACT_DIR];
+ while (pr != NULL) {
+ if (strcmp(name, pr->spec) == 0) {
+ if (!pass_rule(pr, mode, uid, gid))
+ retval++;
+ else
+ rules_matched++; // Exact match found
+ }
+ pr = pr->next;
+ }
+
+ if ((retval + rules_matched) > 1)
+ printf("# WARNING # Multiple exact rules for directory: %s\n", name);
+
+ // If any exact rule matched or failed, we are done with this directory
+ if (retval)
+ print_new_rule(name, mode, uid, gid);
+ if (rules_matched || retval)
+ return retval;
+
+ pr = rules[RECURSIVE];
+ while (pr != NULL) {
+ if (strstr(name, pr->spec) == name) {
+ if (!pass_rule(pr, mode, uid, gid))
+ retval++;
+ else
+ rules_matched++;
+ }
+ pr = pr->next;
+ }
+
+ if (!rules_matched)
+ retval++; // In case no rules either matched or failed, be sure to fail
+
+ if (retval)
+ print_new_rule(name, mode, uid, gid);
+
+ return retval;
+}
+
+// Returns 0 on success
+static int check_path(const char *name)
+{
+ char namebuf[MAX_NAME_LEN + 1];
+ char tmp[MAX_NAME_LEN + 1];
+ DIR *d;
+ struct dirent *de;
+ struct stat s;
+ int err;
+ int retval = 0;
+
+ err = lstat(name, &s);
+ if (err < 0) {
+ if (errno != ENOENT)
+ {
+ perror(name);
+ return 1;
+ }
+ return 0; // File doesn't exist anymore
+ }
+
+ if (S_ISDIR(s.st_mode)) {
+ if (name[strlen(name) - 1] != '/')
+ snprintf(namebuf, sizeof(namebuf), "%s/", name);
+ else
+ snprintf(namebuf, sizeof(namebuf), "%s", name);
+
+ retval |= validate_dir(namebuf, PERMS(s.st_mode), s.st_uid, s.st_gid);
+ d = opendir(namebuf);
+ if(d == 0) {
+ printf("%s : opendir failed: %s\n", namebuf, strerror(errno));
+ return 1;
+ }
+
+ while ((de = readdir(d)) != 0) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+ snprintf(tmp, sizeof(tmp), "%s%s", namebuf, de->d_name);
+ retval |= check_path(tmp);
+ }
+ closedir(d);
+ return retval;
+ } else if (S_ISLNK(s.st_mode)) {
+ return validate_link(name, PERMS(s.st_mode), s.st_uid, s.st_gid);
+ } else {
+ return validate_file(name, PERMS(s.st_mode), s.st_uid, s.st_gid);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ FILE *fp;
+ int i;
+
+ // Initialize ruleset pointers
+ for (i = 0; i < NUM_PR_TYPES; i++)
+ rules[i] = NULL;
+
+ if (!(fp = fopen("/etc/perm_checker.conf", "r"))) {
+ printf("Error opening /etc/perm_checker.conf\n");
+ exit(255);
+ }
+ read_rules(fp);
+ fclose(fp);
+
+ if (check_path("/"))
+ return 255;
+
+ printf("Passed.\n");
+ return 0;
+}
diff --git a/tests/fstest/perm_checker.conf b/tests/fstest/perm_checker.conf
new file mode 100644
index 00000000..fe253d7b
--- /dev/null
+++ b/tests/fstest/perm_checker.conf
@@ -0,0 +1,165 @@
+/ 755 755 root root root root
+/* 400 755 root root root root
+/cache/ 770 770 system system cache cache
+/cache/... 770 770 system system cache cache
+/cache/lost+found/ 700 770 root root root root
+/d/ 755 755 root root root root
+/d/... 000 770 root root root root
+/data/ 771 771 system system system system
+/data/* 000 744 system system system system
+/data/anr/ 000 751 root system log log
+/data/anr/... 000 662 root system log log
+/data/app/ 771 771 system system system system
+/data/app/... 644 664 system system system system
+/data/app-private/ 700 771 system system system system
+/data/dalvik-cache/ 750 771 root system root system
+/data/dalvik-cache/... 400 744 root 19999 root 19999
+/data/data 701 771 system system system system
+/data/data/... 000 775 system 19999 system 19999
+/data/local/ 771 771 shell shell shell shell
+/data/local/tmp/ 771 1771 shell shell shell shell
+/data/lost+found/ 700 770 root root root root
+/data/misc/ 1711 1771 root system root misc
+/data/misc/akmd_set.txt 600 640 root compass compass compass
+/data/misc/rild* 600 660 root radio root radio
+/data/misc/dhcp/ 700 770 root dhcp dhcp dhcp
+/data/misc/dhcp/... 000 660 root dhcp dhcp dhcp
+/data/misc/hcid/ 700 770 root bluetooth bluetooth bluetooth
+/data/misc/hcid/... 600 770 root bluetooth bluetooth bluetooth
+/data/misc/wifi/ 000 1771 system wifi system wifi
+/data/misc/wifi/... 000 770 root wifi root wifi
+/data/property/ 700 770 root root root root
+/data/property/... 600 660 root root root root
+/data/system/ 000 775 system system system system
+/data/system/... 000 774 system system system system
+/data/testinfo/ 770 771 root system root system
+/data/testinfo/* 000 664 root system root system
+/data/tombstones/ 755 755 system system system system
+/data/tombstones/* 000 600 system 19999 system 19999
+/dev/ 755 755 root root root root
+/dev/alarm 600 664 root radio root radio
+/dev/ashmem 666 666 root root root root
+/dev/android_adb 600 660 root adb root adb
+/dev/android_adb_enable 600 660 root adb root adb
+/dev/android_ums 640 640 mount mount mount mount
+/dev/binder 666 666 root root root root
+/dev/console 600 600 root root root root
+/dev/full 666 666 root root root root
+/dev/hw3d 660 660 system system graphics graphics
+/dev/htc-acoustic 600 640 radio radio radio radio
+/dev/network_throughput 600 660 root system root system
+/dev/network_latency 600 660 root system root system
+/dev/cpu_dma_latency 600 660 root system root system
+/dev/mem 600 600 root root root root
+/dev/msm_mp3 600 660 root system root audio
+/dev/msm_pcm_ctl 660 660 system system audio audio
+/dev/msm_pcm_in 660 660 system system audio audio
+/dev/msm_pcm_out 660 660 system system audio audio
+/dev/msm_perf 600 600 root root root root
+/dev/null 666 666 root root root root
+/dev/pmem 660 660 system system graphics graphics
+/dev/pmem_adsp 660 660 system system audio audio
+/dev/pmem_camera 600 660 root system root camera
+/dev/ppp 600 600 root root root root
+/dev/psaux 600 600 root root root root
+/dev/ptmx 666 666 root root root root
+/dev/random 666 666 root root root root
+/dev/smd0 640 640 radio radio radio radio
+/dev/ttyMSM0 600 600 bluetooth bluetooth bluetooth bluetooth
+/dev/urandom 666 666 root root root root
+/dev/zero 666 666 root root root root
+/dev/akm* 640 640 compass compass system system
+/dev/km* 600 600 root root root root
+/dev/mt9* 600 660 system system system system
+/dev/pmem_gpu* 660 660 system system graphics graphics
+/dev/qmi* 600 640 radio radio radio radio
+/dev/rtc* 600 600 root root root root
+/dev/smd* 600 600 root root root root
+/dev/tty* 600 600 root root root root
+/dev/vc* 600 600 root root root root
+/dev/adsp/ 750 755 root root root root
+/dev/adsp/* 660 660 system system audio audio
+/dev/block/ 750 775 root root root root
+/dev/block/* 600 600 root root root root
+/dev/graphics/ 755 755 root root root root
+/dev/graphics/* 660 660 root root graphics graphics
+/dev/input/ 755 755 root root root root
+/dev/input/* 660 660 root root input input
+/dev/log/ 755 755 root root root root
+/dev/log/* 662 662 root root log log
+/dev/oncrpc/ 755 755 root root root root
+/dev/oncrpc/... 000 660 root camera root camera
+/dev/pts/ 755 755 root root root root
+/dev/pts/* 600 600 root shell root shell
+/dev/mtd/ 750 775 root root root root
+/dev/mtd/mtd0 460 460 radio radio diag diag
+/dev/mtd/* 600 600 root root root root
+/dev/socket/ 750 755 root system root system
+/dev/socket/bluetooth 600 660 root bluetooth bluetooth bluetooth
+/dev/socket/dbus 660 660 root bluetooth bluetooth bluetooth
+/dev/socket/dbus_bluetooth 600 660 root bluetooth bluetooth bluetooth
+/dev/socket/installd 600 660 system system system system
+/dev/socket/mountd 660 660 root mount root mount
+/dev/socket/property_service 666 666 root system root system
+/dev/socket/rild 660 660 root radio root radio
+/dev/socket/rild-debug 660 660 root radio root radio
+/dev/socket/usbd 660 660 root mount mount mount
+/dev/socket/wpa_* 600 660 root wifi wifi wifi
+/dev/socket/zygote 666 666 root root root root
+/etc 777 777 root root root root
+/proc/ 555 555 root root root root
+/proc/... 000 777 root 19999 root 19999
+/proc/sys/kernel/sched_nr_migrate 000 1664 root root root root
+/root/ 700 700 root root root root
+/sdcard/ 000 077 system system system system
+/sdcard/... 000 077 system system system system
+/sbin/ 700 770 root root root root
+/sbin/... 700 775 root root root root
+/sys/ 755 775 root system root system
+/sys/... 000 775 root system root system
+/sys/android_power/acquire_full_wake_lock 664 664 radio radio system system
+/sys/android_power/acquire_partial_wake_lock 664 664 radio radio system system
+/sys/android_power/release_wake_lock 664 664 radio radio system system
+/sys/android_power/request_state 664 664 radio radio system system
+/sys/android_power/state 664 664 radio radio system system
+/sys/module/board_trout/parameters/bluetooth_power_on 660 660 root bluetooth bluetooth bluetooth
+/sys/qemu_trace/process_name 000 777 root system root system
+/sys/qemu_trace/state 000 777 root system root system
+/sys/qemu_trace/symbol 000 777 root system root system
+/system/ 755 755 root root root root
+/system/* 000 664 root system root system
+/system/app/ 755 755 root root root root
+/system/app/... 600 644 root root root root
+/system/bin/... 000 755 root shell root shell
+/system/bin/netcfg 000 2750 root root inet inet
+/system/bin/ping 000 2755 root root net_raw net_raw
+/system/etc/ 755 755 root root root root
+/system/etc/... 000 664 root bluetooth root audio
+/system/etc/firmware/ 700 755 root root root root
+/system/etc/init.goldfish.sh 500 550 root root root shell
+/system/etc/init.gprs-pppd 500 550 root root root shell
+/system/etc/init.testmenu 500 550 root root root root
+/system/etc/perm_checker.conf 000 777 root shell root shell
+/system/etc/ppp/ 755 775 root system root system
+/system/etc/ppp/chap-secrets 600 660 root system root system
+/system/etc/ppp/ip-down 500 550 root system root system
+/system/etc/ppp/ip-up 500 550 root system root system
+/system/etc/security/ 755 755 root root root root
+/system/etc/wifi/ 750 755 root system root system
+/system/lib/ 755 755 root root root root
+/system/lib/... 600 644 root root root root
+/system/lib/modules/ 755 755 root root root root
+/system/lost+found/ 700 770 root root root root
+/system/fonts/ 755 755 root root root root
+/system/fonts/... 644 644 root root root root
+/system/framework/ 755 755 root root root root
+/system/framework/... 600 644 root root root root
+/system/media/ 755 755 root root root root
+/system/media/... 644 644 root root root root
+/system/media/audio/ 755 755 root root root root
+/system/media/audio/notifications/ 755 755 root root root root
+/system/media/audio/ringtones/ 755 755 root root root root
+/system/sounds/ 755 755 root root root root
+/system/sounds/... 644 644 root root root root
+/system/usr/... 400 755 root root root root
+/sqlite_stmt_journals/ 1777 1777 root root root root
diff --git a/tests/icachetest/Android.mk b/tests/icachetest/Android.mk
new file mode 100644
index 00000000..fca07ee1
--- /dev/null
+++ b/tests/icachetest/Android.mk
@@ -0,0 +1,14 @@
+# 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 := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/icachetest/icache.S b/tests/icachetest/icache.S
new file mode 100644
index 00000000..e5a24277
--- /dev/null
+++ b/tests/icachetest/icache.S
@@ -0,0 +1,180 @@
+/*
+ * icache.s
+ *
+ *
+ * Copyright 2005 The Android Open Source Project
+ *
+ */
+
+ .text
+ .global icache_test
+ .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 00000000..5e06dba9
--- /dev/null
+++ b/tests/icachetest/icache2.S
@@ -0,0 +1,170 @@
+/*
+ * icache.s
+ *
+ *
+ * Copyright 2005 The Android Open Source Project
+ *
+ */
+
+ .text
+ .align
+
+ .global icache_test2
+
+#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 00000000..93f36d47
--- /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/memtest/Android.mk b/tests/memtest/Android.mk
new file mode 100644
index 00000000..36f233c7
--- /dev/null
+++ b/tests/memtest/Android.mk
@@ -0,0 +1,19 @@
+# Copyright 2006 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= memtest.cpp.arm \
+ thumb.cpp
+
+
+LOCAL_SHARED_LIBRARIES := libc
+
+LOCAL_MODULE:= memtest
+
+LOCAL_MODULE_TAGS := tests
+
+## LOCAL_CFLAGS += -fstack-protector-all
+LOCAL_CFLAGS += -fomit-frame-pointer
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/memtest/memtest.cpp b/tests/memtest/memtest.cpp
new file mode 100644
index 00000000..d6cc9b21
--- /dev/null
+++ b/tests/memtest/memtest.cpp
@@ -0,0 +1,763 @@
+/*
+ * 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>
+
+#if 0
+const int DCACHE_SIZE = 8*1024;
+const int CPU_FREQ_EST = 195;
+const int BRANCH_CYCLE = 3;
+#else
+const int DCACHE_SIZE = 32*1024;
+const int CPU_FREQ_EST = 384;
+const int BRANCH_CYCLE = 2;
+#endif
+
+typedef long long nsecs_t;
+
+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;
+}
+
+nsecs_t loop_overhead(size_t count) __attribute__((noinline));
+nsecs_t loop_overhead(size_t count)
+{
+ nsecs_t overhead = -system_time();
+ do {
+ asm volatile ("":::"memory");
+ } while (--count);
+ overhead += system_time();
+ return overhead;
+}
+
+static void preload(volatile char* addr, size_t s)
+{
+ for (size_t i=0 ; i<s ; i+=32) {
+ char c = addr[i];
+ (void)c;
+ }
+}
+
+static void usage(char* p) {
+ printf( "Usage: %s <test> <options>\n"
+ "<test> is one of the following:\n"
+ " cpufreq\n"
+ " memcpy [perf [fast] | test]\n"
+ " memset [perf | test]\n"
+ " memcmp [perf | test]\n"
+ " strlen [perf | test]\n"
+ " malloc [fill]\n"
+ " madvise\n"
+ " resampler\n"
+ " crash\n"
+ " stack (stack smasher)\n"
+ " crawl\n"
+ , p);
+}
+
+int cpufreq_test(int argc, char** argv);
+int memcpy_test(int argc, char** argv);
+int memset_test(int argc, char** argv);
+int memcmp_test(int argc, char** argv);
+int strlen_test(int argc, char** argv);
+int malloc_test(int argc, char** argv);
+int madvise_test(int argc, char** argv);
+int crash_test(int argc, char** argv);
+int stack_smasher_test(int argc, char** argv);
+int crawl_test(int argc, char** argv);
+
+#if 0
+#pragma mark -
+#pragma mark main
+#endif
+
+int main(int argc, char** argv)
+{
+ if (argc == 1) {
+ usage(argv[0]);
+ return 0;
+ }
+ int err = -1;
+ if (!strcmp(argv[1], "cpufreq")) err = cpufreq_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "memcpy")) err = memcpy_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "memset")) err = memset_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "memcmp")) err = memcmp_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "strlen")) err = strlen_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "malloc")) err = malloc_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "madvise")) err = madvise_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "crash")) err = crash_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "stack")) err = stack_smasher_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "crawl")) err = crawl_test(argc-1, argv+1);
+ if (err) {
+ usage(argv[0]);
+ }
+ return 0;
+}
+
+#if 0
+#pragma mark -
+#pragma mark memcpy
+#endif
+
+int validate_memcpy(char* s, char* d, size_t size);
+int validate_memset(char* s, char c, size_t size);
+
+int memcpy_test(int argc, char** argv)
+{
+ int option = 0;
+ if (argc >= 2) {
+ if (!strcmp(argv[1], "perf")) option = 0;
+ else if (!strcmp(argv[1], "test")) option = 1;
+ else return -1;
+ }
+
+ const int MAX_SIZE = 1024*1024; // 1MB
+ const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 150 MB/s
+ const int UNCACHED_SPEED_EST = (CPU_FREQ_EST/4)*1024*1024; // 60 MB/s
+ char* src = (char*)malloc(MAX_SIZE+4+8+32);
+ char* dst = (char*)malloc(MAX_SIZE+4+8+32);
+ memset(src, 0, MAX_SIZE+4+8+32);
+ memset(dst, 0, MAX_SIZE+4+8+32);
+
+ if (option == 0) {
+ bool fast = (argc>=3 && !strcmp(argv[2], "fast"));
+ printf("memcpy() performance test is running, please wait...\n");
+ fflush(stdout);
+ usleep(10000);
+ setpriority(PRIO_PROCESS, 0, -20);
+ static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
+
+ struct result_t { int size; float res; };
+ result_t* results = (result_t*)src;
+ int nbr = 0;
+ int size = 0;
+ for (int i=0 ; ; i++) {
+ if (!fast) {
+ if (size<128) size += 8;
+ else if (size<1024) size += 128;
+ else if (size<16384) size += 1024;
+ else size <<= 1;
+ } else {
+ if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
+ break;
+ size = FAST_SIZES[i];
+ }
+ if (size > MAX_SIZE) {
+ break;
+ }
+
+ const int REPEAT = (((size < DCACHE_SIZE) ?
+ (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size) / 2;
+ // ~0.5 second per test
+
+ const nsecs_t overhead = loop_overhead(REPEAT);
+
+ // tweak to make it a bad case
+ char* ddd = (char*)((long(dst+31)&~31) + 4);
+ char* sss = (char*)((long(src+31)&~31) + 28);
+
+ for (int offset=0 ; offset<=2 ; offset +=2 ) {
+ memcpy(dst, src, size); // just make sure to load the caches I/D
+ nsecs_t t = -system_time();
+ register int count = REPEAT;
+ do {
+ memcpy(ddd, sss+offset, size);
+ } while (--count);
+ t += system_time() - overhead;
+ const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
+ results[nbr].size = size;
+ results[nbr].res = throughput;
+ nbr++;
+ }
+ }
+
+ printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (nc)");
+ for (int i=0 ; i<nbr ; i+=2) {
+ printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
+ }
+ } else if (option == 1) {
+ printf("memcpy() validation test is running, please wait...\n");
+ fflush(stdout);
+ char* curr = (char*)src;
+ for (int i=0 ; i<MAX_SIZE ; i++) {
+ char c = rand();
+ *curr++ = c != 0x55 ? c : 0xAA;
+ }
+ char* s = src + 1024;
+ char* d = dst + 1024;
+ int nb = 0;
+ for (int size=0 ; size<4096 && !nb ; size++) {
+ nb += validate_memcpy(s, d, size);
+ for (int o=1 ; o<32 && !nb ; o++) {
+ nb += validate_memcpy(s+o, d, size);
+ nb += validate_memcpy(s, d+o, size);
+ nb += validate_memcpy(s+o, d+o, size);
+ }
+ }
+ if (nb) printf("%d error(s) found\n", nb);
+ else printf("success!\n");
+ }
+ fflush(stdout);
+ free(dst);
+ free(src);
+ return 0;
+}
+
+int validate_memcpy(char* s, char* d, size_t size)
+{
+ int nberr = 0;
+ memset(d-4, 0x55, size+8);
+ memcpy(s, d, size);
+ if (memcmp(s,d,size)) {
+ printf("*** memcpy(%p,%p,%lu) destination != source\n",s,d,size);
+ nberr++;
+ }
+ bool r = (d[size]==0x55)&&(d[size+1]==0x55)&&(d[size+2]==0x55)&&(d[size+3]==0x55);
+ if (!r) {
+ printf("*** memcpy(%p,%p,%lu) clobbered past end of destination!\n",s,d,size);
+ nberr++;
+ }
+ r = (d[-1]==0x55)&&(d[-2]==0x55)&&(d[-3]==0x55)&&(d[-4]==0x55);
+ if (!r) {
+ printf("*** memcpy(%p,%p,%lu) clobbered before start of destination!\n",s,d,size);
+ nberr++;
+ }
+ return nberr;
+}
+
+
+#if 0
+#pragma mark -
+#pragma mark memset
+#endif
+
+int memset_test(int argc, char** argv)
+{
+ int option = 0;
+ if (argc >= 2) {
+ if (!strcmp(argv[1], "perf")) option = 0;
+ else if (!strcmp(argv[1], "test")) option = 1;
+ else return -1;
+ }
+
+ const int MAX_SIZE = 1024*1024; // 1MB
+ const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
+ const int UNCACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
+ char* dst = (char*)malloc(MAX_SIZE+4+8);
+
+ if (option == 0) {
+ printf("memset() performance test is running, please wait...\n");
+ fflush(stdout);
+ usleep(10000);
+ setpriority(PRIO_PROCESS, 0, -20);
+
+ static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
+ const size_t FAST_SIZES_COUNT = sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]);
+ struct result_t { int size; float res; };
+ result_t results[FAST_SIZES_COUNT*2];
+ int nbr = 0;
+ int size = 0;
+ for (int i=0 ; ; i++) {
+ if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
+ break;
+ size = FAST_SIZES[i];
+ if (size > MAX_SIZE) {
+ break;
+ }
+ const int REPEAT = (((size < DCACHE_SIZE) ?
+ (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size);
+ // ~0.5 second per test
+
+ const nsecs_t overhead = loop_overhead(REPEAT);
+
+ for (int j=0 ; j<2 ; j++) {
+ if (j==0) preload(dst, DCACHE_SIZE*4); // flush D
+ else preload(dst, size); // load D
+ nsecs_t t = -system_time();
+ size_t count = REPEAT;
+ do {
+ memset(dst, 0, size);
+ } while (--count);
+ t += system_time() - overhead;
+
+ const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
+ results[nbr].size = size;
+ results[nbr].res = throughput;
+ nbr++;
+ }
+ }
+
+ printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (cached)");
+ for (int i=0 ; i<nbr ; i+=2) {
+ printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
+ }
+ } else if (option == 1) {
+ printf("memset() validation test is running, please wait...\n");
+ fflush(stdout);
+ char* d = dst + 1024;
+ int nb = 0;
+ for (int o=1 ; o<32 ; o++) {
+ for (int size=0 ; size<4096 && !nb ; size++) {
+ nb += validate_memset(d, char(o), size);
+ nb += validate_memset(d+o, char(o), size);
+ }
+ }
+ if (nb) printf("%d error(s) found\n", nb);
+ else printf("success!\n");
+ }
+ fflush(stdout);
+ free(dst);
+ return 0;
+}
+
+int validate_memset(char* d, char c, size_t size)
+{
+ int nberr = 0;
+ for (size_t i=0; i<size ; d[i++]=0xaa) ;
+ d[-1] = 0x55;
+ d[size+1] = 0x55;
+ memset(d, c, size);
+ if (d[size+1]!=0x55) {
+ printf("*** memset(%p,%02x,%lu) clobbered past end of destination!\n",d,(int)c,size);
+ nberr++;
+ }
+ if (d[-1]!=0x55) {
+ printf("*** memset(%p,%02x,%lu) clobbered before start of destination!\n",d,(int)c,size);
+ nberr++;
+ }
+ for (size_t i=0 ; i<size ; i++) {
+ if (d[i] != c) {
+ printf("*** memset(%p,%02x,%lu) failed at offset %lu\n",d,(int)c,size, i);
+ nberr++;
+ break;
+ }
+ }
+ return nberr;
+}
+
+#if 0
+#pragma mark -
+#pragma mark memcmp
+#endif
+
+static int ref_memcmp(const void *s1, const void *s2, size_t n)
+{
+ const unsigned char *c1 = (const unsigned char *)s1, *c2 = (const unsigned char *)s2;
+ int d = 0;
+
+ while ( n-- ) {
+ d = (int)*c1++ - (int)*c2++;
+ if ( d )
+ break;
+ }
+
+ return d;
+}
+
+int validate_memcmp(const char* s, const char* d, size_t size)
+{
+
+ int a = ref_memcmp(s, d, size);
+ int b = memcmp(s, d, size);
+ //printf("%d, %d\n", a, b);
+ if (a != b) {
+ printf("*** memcmp(%p,%p,%lu) failed %d should be %d\n",s,d,size,b,a);
+ return 1;
+ }
+ return 0;
+}
+
+int memcmp_test(int argc, char** argv)
+{
+ int option = 0;
+ if (argc >= 2) {
+ if (!strcmp(argv[1], "perf")) option = 0;
+ else if (!strcmp(argv[1], "test")) option = 1;
+ else return -1;
+ }
+
+ const int MAX_SIZE = 1024*1024; // 1MB
+ const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 150 MB/s
+ const int UNCACHED_SPEED_EST = (CPU_FREQ_EST/4)*1024*1024; // 60 MB/s
+ char* src = (char*)malloc(MAX_SIZE+4+8+32);
+ char* dst = (char*)malloc(MAX_SIZE+4+8+32);
+
+ if (option == 0) {
+ printf("memcmp() performance test is running, please wait...\n");
+ fflush(stdout);
+ usleep(10000);
+ setpriority(PRIO_PROCESS, 0, -20);
+
+ static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
+
+ struct result_t { int size; float res; };
+ result_t* results = (result_t*)src;
+ int nbr = 0;
+ int size = 0;
+ for (int i=0 ; ; i++) {
+ if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
+ break;
+ size = FAST_SIZES[i];
+ if (size > MAX_SIZE) {
+ break;
+ }
+
+ const int REPEAT = (((size < DCACHE_SIZE) ?
+ (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size) / 2;
+ // ~0.5 second per test
+
+ const nsecs_t overhead = loop_overhead(REPEAT);
+
+ // tweak to make it a bad case
+ char* ddd = (char*)((long(dst+31)&~31) + 4);
+ char* sss = (char*)((long(src+31)&~31) + 28);
+
+ for (int offset=0 ; offset<=2 ; offset +=2 ) {
+ memcpy(ddd, sss+offset, size); // just make sure to load the caches I/D
+ nsecs_t t = -system_time();
+ register int count = REPEAT;
+ char c;
+ c = memcmp(ddd, sss+offset, size);
+ //printf("size %d, memcmp -> %d\n", size, (int)c);
+ do {
+ c = memcmp(ddd, sss+offset, size);
+ asm volatile (""::"r"(c):"memory");
+ } while (--count);
+ t += system_time() - overhead;
+ const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
+ results[nbr].size = size;
+ results[nbr].res = throughput;
+ nbr++;
+ }
+ }
+
+ printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (nc)");
+ for (int i=0 ; i<nbr ; i+=2) {
+ printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
+ }
+ } else {
+ printf("memcmp() validation test is running, please wait...\n");
+ fflush(stdout);
+
+ const char* const s = (const char*)src + 1024;
+ const char* const d = (const char*)dst + 1024;
+ int nb = 0;
+ for (int j=0 ; j<32 ; j++) {
+
+ char *curr0 = (char*)src;
+ char *curr1 = (char*)dst;
+ for (int i=0 ; i<MAX_SIZE ; i++) {
+ char c = rand();
+ *curr0++ = c;
+ *curr1++ = c;
+ }
+ if (j) {
+ src[1024 + j] ^= 0xFF;
+ }
+
+
+ for (int size=0 ; size<32 && !nb ; size++) {
+ for (int o=0 ; o<4 ; o++) {
+ nb += validate_memcmp(s+o, d+o, size);
+ }
+ // memmove((char*)d+1, d, size);
+ for (int o=0 ; o<4 ; o++) {
+ nb += validate_memcmp(s, d+o, size);
+ }
+ }
+ }
+ if (nb) printf("%d error(s) found\n", nb);
+ else printf("success!\n");
+ }
+ fflush(stdout);
+ free(dst);
+ free(src);
+ return 0;
+}
+
+#if 0
+#pragma mark -
+#pragma mark strlen
+#endif
+
+int strlen_test(int argc, char** argv)
+{
+ int option = 0;
+ if (argc >= 2) {
+ if (!strcmp(argv[1], "perf")) option = 0;
+ else if (!strcmp(argv[1], "test")) option = 1;
+ else return -1;
+ }
+
+ const int MAX_SIZE = 1024*1024; // 1MB
+ const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
+ const int UNCACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
+ char* str = (char*)calloc(MAX_SIZE+4+8, 1);
+
+ if (option == 0) {
+ printf("strlen() performance test is running, please wait...\n");
+ fflush(stdout);
+ usleep(10000);
+ setpriority(PRIO_PROCESS, 0, -20);
+
+ static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
+ const size_t FAST_SIZES_COUNT = sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]);
+ struct result_t { int size; float res; };
+ result_t results[FAST_SIZES_COUNT*2];
+ int nbr = 0;
+ int size = 0;
+ for (int i=0 ; ; i++) {
+ if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
+ break;
+ size = FAST_SIZES[i];
+ if (size > MAX_SIZE) {
+ break;
+ }
+ const int REPEAT = (((size < DCACHE_SIZE) ?
+ (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size);
+ // ~0.5 second per test
+
+ const nsecs_t overhead = loop_overhead(REPEAT);
+
+ for (int j=0 ; j<2 ; j++) {
+ memset(str, 'A', size-1);
+ if (j==0) preload(str, DCACHE_SIZE*4); // flush D
+ else preload(str, size); // load D
+
+ nsecs_t t = -system_time();
+ size_t count = REPEAT;
+ int c=0;
+ do {
+ c = strlen(str);
+ asm volatile (""::"r"(c):"memory");
+ } while (--count);
+ t += system_time() - overhead;
+
+ const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
+ results[nbr].size = size;
+ results[nbr].res = throughput;
+ nbr++;
+ }
+ }
+
+ printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (cached)");
+ for (int i=0 ; i<nbr ; i+=2) {
+ printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
+ }
+ }
+
+ fflush(stdout);
+ free(str);
+ return 0;
+}
+
+
+#if 0
+#pragma mark -
+#pragma mark malloc
+#endif
+
+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 = %9lu failed\n", size);
+ size >>= 1;
+ } else {
+ total += size;
+ printf("size = %9lu, addr = %p (total = %9lu (%lu 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 %lu MB\n", total / (1024*1024));
+ return 0;
+}
+
+#if 0
+#pragma mark -
+#pragma mark madvise
+#endif
+
+int madvise_test(int argc, char** argv)
+{
+ for (int i=0 ; i<2 ; i++) {
+ size_t size = i==0 ? 4096 : 48*1024*1024; // 48 MB
+ printf("Allocating %lu 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 %lu 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;
+}
+
+#if 0
+#pragma mark -
+#pragma mark cpufreq
+#endif
+
+int cpufreq_test(int argc, char** argv)
+{
+ struct timespec res;
+ clock_getres(CLOCK_REALTIME, &res);
+ printf("CLOCK_REALTIME resolution: %lu ns\n", res.tv_nsec);
+ clock_getres(CLOCK_MONOTONIC, &res);
+ printf("CLOCK_MONOTONIC resolution: %lu ns\n", res.tv_nsec);
+ clock_getres(CLOCK_PROCESS_CPUTIME_ID, &res);
+ printf("CLOCK_PROCESS_CPUTIME_ID resolution: %lu ns\n", res.tv_nsec);
+ clock_getres(CLOCK_THREAD_CPUTIME_ID, &res);
+ printf("CLOCK_THREAD_CPUTIME_ID resolution: %lu ns\n", res.tv_nsec);
+
+ if (clock_getres(CLOCK_REALTIME_HR, &res) != 0)
+ printf("CLOCK_REALTIME_HR resolution: %lu ns\n", res.tv_nsec);
+ else
+ printf("CLOCK_REALTIME_HR not supported\n");
+
+ if (clock_getres(CLOCK_MONOTONIC_HR, &res) != 0)
+ printf("CLOCK_MONOTONIC_HR resolution: %lu ns\n", res.tv_nsec);
+ else
+ printf("CLOCK_MONOTONIC_HR not supported\n");
+
+ printf("\nEstimating the CPU frequency, please wait...\n");
+ fflush(stdout);
+ usleep(10000);
+ setpriority(PRIO_PROCESS, 0, -20);
+
+ const int LOOP_CYCLES = 1+BRANCH_CYCLE; // 1 cycle + 3 cycles for the branch
+ const size_t REPEAT = CPU_FREQ_EST*1000000; // ~4 seconds (4cycles/loop)
+ register size_t count = REPEAT;
+ nsecs_t t = system_time();
+ do { // this loop generates 1+3 cycles
+ asm volatile ("":::"memory");
+ } while (--count);
+ t = system_time() - t;
+ const float freq = t ? (1000.0f*float(REPEAT)*LOOP_CYCLES) / t : 0;
+ printf("this CPU frequency: %ld MHz\n", long(freq+0.5f));
+ return 0;
+}
+
+#if 0
+#pragma mark -
+#pragma mark crash_test
+#endif
+
+int crash_test(int argc, char** argv)
+{
+ printf("about to crash...\n");
+ asm volatile(
+ "mov r0, #0 \n"
+ "mov r1, #1 \n"
+ "mov r2, #2 \n"
+ "mov r3, #3 \n"
+ "ldr r12, [r0] \n"
+ );
+
+ return 0;
+}
+
+int stack_smasher_test(int argc, char** argv)
+{
+ 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*p) {
+ int a = 0;
+ thumb_function_2(&a);
+}
+
+void arm_function_2(int*p) {
+ int a = 0;
+ thumb_function_1(&a);
+}
+
+void arm_function_1(int*p) {
+ int a = 0;
+ arm_function_2(&a);
+}
+
+int crawl_test(int argc, char** argv)
+{
+ int a = 0;
+ arm_function_1(&a);
+ return 0;
+}
+
diff --git a/tests/memtest/thumb.cpp b/tests/memtest/thumb.cpp
new file mode 100644
index 00000000..a70f4c3b
--- /dev/null
+++ b/tests/memtest/thumb.cpp
@@ -0,0 +1,27 @@
+#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 *arg)
+{
+ int i = 0;
+ printf("0x%x\n", _Unwind_GetIP(context));
+ fflush(stdout);
+ return _URC_NO_REASON;
+}
+
+void thumb_function_1(int*p)
+{
+ int a = 0;
+ arm_function_3(&a);
+}
+
+void thumb_function_2(int*p)
+{
+ int a = 0;
+ printf("unwinding...\n");
+ _Unwind_Backtrace(trace_function, (void*)"backtrace!");
+}
diff --git a/tests/schedtest/Android.mk b/tests/schedtest/Android.mk
new file mode 100644
index 00000000..58e8d62b
--- /dev/null
+++ b/tests/schedtest/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ schedtest.c
+
+LOCAL_MODULE := schedtest
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/schedtest/schedtest.c b/tests/schedtest/schedtest.c
new file mode 100644
index 00000000..f15b66b3
--- /dev/null
+++ b/tests/schedtest/schedtest.c
@@ -0,0 +1,48 @@
+/*
+** 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/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/timeinfo/Android.mk b/timeinfo/Android.mk
new file mode 100644
index 00000000..5c4672ea
--- /dev/null
+++ b/timeinfo/Android.mk
@@ -0,0 +1,24 @@
+# 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 := timeinfo
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := tests eng
+LOCAL_SRC_FILES := timeinfo.cpp
+LOCAL_SHARED_LIBRARIES := libhardware_legacy
+include $(BUILD_EXECUTABLE)
diff --git a/timeinfo/timeinfo.cpp b/timeinfo/timeinfo.cpp
new file mode 100644
index 00000000..b1af7ced
--- /dev/null
+++ b/timeinfo/timeinfo.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/* Report realtime, uptime, awake percentage, and sleep percentage to stdout.
+ * Primarily called by powerdroid test harness.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "utils/SystemClock.h"
+
+
+int main(int argc, char *argv[])
+{
+
+ int64_t realtime, uptime;
+ int64_t awaketime, sleeptime;
+
+ uptime = android::uptimeMillis();
+ realtime = android::elapsedRealtime();
+
+ if (realtime == 0) {
+ realtime = 1;
+ }
+
+ awaketime = ((1000 * uptime / realtime) + 5) / 10;
+ sleeptime = ((1000 * (realtime - uptime) / realtime) + 5) / 10;
+
+ printf("%jd %jd %jd %jd\n", (intmax_t) realtime, (intmax_t) uptime,
+ (intmax_t) awaketime, (intmax_t) sleeptime);
+
+}
+
+
+/* vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab */