Merge "Do not resolve to real/absolute link in GCC 4.6 / 4.7"
diff --git a/sources/android/cpufeatures/cpu-features.c b/sources/android/cpufeatures/cpu-features.c
index 02ea74f..b941cdd 100644
--- a/sources/android/cpufeatures/cpu-features.c
+++ b/sources/android/cpufeatures/cpu-features.c
@@ -28,6 +28,8 @@
 
 /* ChangeLog for this library:
  *
+ * NDK r??: Add android_setCpu().
+ *
  * NDK r8c: Add new ARM CPU features: VFPv2, VFP_D32, VFP_FP16,
  *          VFP_FMA, NEON_FMA, IDIV_ARM, IDIV_THUMB2 and iWMMXt.
  *
@@ -66,6 +68,7 @@
 #include <errno.h>
 
 static  pthread_once_t     g_once;
+static  int                g_inited;
 static  AndroidCpuFamily   g_cpuFamily;
 static  uint64_t           g_cpuFeatures;
 static  int                g_cpuCount;
@@ -477,14 +480,30 @@
 }
 
 static void
+android_cpuInitFamily(void)
+{
+#if defined(__ARM_ARCH__)
+    g_cpuFamily = ANDROID_CPU_FAMILY_ARM;
+#elif defined(__i386__)
+    g_cpuFamily = ANDROID_CPU_FAMILY_X86;
+#elif defined(_MIPS_ARCH)
+    g_cpuFamily = ANDROID_CPU_FAMILY_MIPS;
+#else
+    g_cpuFamily = ANDROID_CPU_FAMILY_UNKNOWN;
+#endif
+}
+
+static void
 android_cpuInit(void)
 {
     char* cpuinfo = NULL;
     int   cpuinfo_len;
 
-    g_cpuFamily   = DEFAULT_CPU_FAMILY;
+    android_cpuInitFamily();
+
     g_cpuFeatures = 0;
     g_cpuCount    = 1;
+    g_inited      = 1;
 
     cpuinfo_len = get_file_size("/proc/cpuinfo");
     if (cpuinfo_len < 0) {
@@ -650,8 +669,6 @@
 #endif /* __ARM_ARCH__ */
 
 #ifdef __i386__
-    g_cpuFamily = ANDROID_CPU_FAMILY_X86;
-
     int regs[4];
 
 /* According to http://en.wikipedia.org/wiki/CPUID */
@@ -676,10 +693,6 @@
     }
 #endif
 
-#ifdef _MIPS_ARCH
-    g_cpuFamily = ANDROID_CPU_FAMILY_MIPS;
-#endif /* _MIPS_ARCH */
-
     free(cpuinfo);
 }
 
@@ -707,6 +720,26 @@
     return g_cpuCount;
 }
 
+static void
+android_cpuInitDummy(void)
+{
+    g_inited = 1;
+}
+
+int
+android_setCpu(int cpu_count, uint64_t cpu_features)
+{
+    /* Fail if the library was already initialized. */
+    if (g_inited)
+        return 0;
+
+    android_cpuInitFamily();
+    g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count);
+    g_cpuFeatures = cpu_features;
+    pthread_once(&g_once, android_cpuInitDummy);
+
+    return 1;
+}
 
 /*
  * Technical note: Making sense of ARM's FPU architecture versions.
diff --git a/sources/android/cpufeatures/cpu-features.h b/sources/android/cpufeatures/cpu-features.h
index b6bf2ac..f8553e8 100644
--- a/sources/android/cpufeatures/cpu-features.h
+++ b/sources/android/cpufeatures/cpu-features.h
@@ -177,6 +177,19 @@
 /* Return the number of CPU cores detected on this device. */
 extern int         android_getCpuCount(void);
 
+/* The following is used to force the CPU count and features
+ * mask in sandboxed processes. Under 4.1 and higher, these processes
+ * cannot access /proc, which is the only way to get information from
+ * the kernel about the current hardware (at least on ARM).
+ *
+ * It _must_ be called only once, and before any android_getCpuXXX
+ * function, any other case will fail.
+ *
+ * This function return 1 on success, and 0 on failure.
+ */
+extern int android_setCpu(int      cpu_count,
+                          uint64_t cpu_features);
+
 __END_DECLS
 
 #endif /* CPU_FEATURES_H */
diff --git a/tests/device/test-cpufeatures/jni/Android.mk b/tests/device/test-cpufeatures/jni/Android.mk
index 340f4dd..bc56410 100644
--- a/tests/device/test-cpufeatures/jni/Android.mk
+++ b/tests/device/test-cpufeatures/jni/Android.mk
@@ -6,4 +6,16 @@
 LOCAL_STATIC_LIBRARIES := cpufeatures
 include $(BUILD_EXECUTABLE)
 
+include $(CLEAR_VARS)
+LOCAL_MODULE := test_android_setCpu_1
+LOCAL_SRC_FILES := test_android_setCpu_1.c
+LOCAL_STATIC_LIBRARIES := cpufeatures
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := test_android_setCpu_2
+LOCAL_SRC_FILES := test_android_setCpu_2.c
+LOCAL_STATIC_LIBRARIES := cpufeatures
+include $(BUILD_EXECUTABLE)
+
 $(call import-module,android/cpufeatures)
diff --git a/tests/device/test-cpufeatures/jni/test_android_setCpu_1.c b/tests/device/test-cpufeatures/jni/test_android_setCpu_1.c
new file mode 100644
index 0000000..cb51a5c
--- /dev/null
+++ b/tests/device/test-cpufeatures/jni/test_android_setCpu_1.c
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cpu-features.h"
+
+static void panic(const char* msg) {
+  fprintf(stderr, "ERROR: %s\n", msg);
+  exit(1);
+}
+
+int main(void) {
+  int count, cpu_count = 10;
+  uint64_t features, cpu_features = 0xaabdedf012934839ULL;
+
+  // Check that android_setCpu() can be called at program startup
+  // and that android_getCpuCount() and android_getCpuFeatures()
+  // will return the corresponding values.
+  //
+  printf("Setting cpu_count=%d, features=%08llx\n",
+         cpu_count,
+         cpu_features);
+  if (!android_setCpu(cpu_count, cpu_features))
+    panic("Cannot call android_setCpu() at program startup!");
+
+  count = android_getCpuCount();
+  features = android_getCpuFeatures();
+
+  printf("Retrieved cpu_count=%d, features=%08llx\n",
+         count, features);
+
+  if (count != cpu_count)
+    panic("android_getCpuCount() didn't return expected value!");
+
+  if (features != cpu_features)
+    panic("android_getCpuFeatures() didn't return expected value!");
+
+  // Once one of the android_getXXX functions has been called,
+  // android_setCpu() should always fail.
+  if (android_setCpu(cpu_count, cpu_features))
+    panic("android_setCpu() could be called twice!");
+
+  printf("Second call to android_setCpu() failed as expected.\n");
+  return 0;
+}
+
diff --git a/tests/device/test-cpufeatures/jni/test_android_setCpu_2.c b/tests/device/test-cpufeatures/jni/test_android_setCpu_2.c
new file mode 100644
index 0000000..2466066
--- /dev/null
+++ b/tests/device/test-cpufeatures/jni/test_android_setCpu_2.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cpu-features.h"
+
+static void panic(const char* msg) {
+  fprintf(stderr, "ERROR: %s\n", msg);
+  exit(1);
+}
+
+int main(void) {
+  int count, cpu_count = 10;
+  uint64_t features, cpu_features = 0xaabdedf012934839ULL;
+
+  count = android_getCpuCount();
+  features = android_getCpuFeatures();
+
+  printf("Retrieved cpu_count=%d, features=%08llx\n",
+         count, features);
+
+  // Check that android_setCpu() will fail when it is called after
+  // android_getCpuCount / android_getCpuFeatures.
+  //
+  printf("Trying to set cpu_count=%d, features=%08llx\n",
+         cpu_count,
+         cpu_features);
+
+  if (android_setCpu(cpu_count, cpu_features))
+    panic("android_setCpu() call should have failed!");
+
+  printf("android_setCpu() call fail as expected.\n");
+  return 0;
+}
diff --git a/tests/run-tests.sh b/tests/run-tests.sh
index bc931bd..48ba4ef 100755
--- a/tests/run-tests.sh
+++ b/tests/run-tests.sh
@@ -576,24 +576,42 @@
         local PROGRAMS=
         local PROGRAM
         # Do not run the test if BROKEN_RUN is defined
-        if [ -f "$TEST/BROKEN_RUN" -o -f "$TEST/BROKEN_BUILD" ] ; then
-	    if [ -z "$RUN_TESTS" ]; then
-		dump "Skipping NDK device test run: `basename $TEST`"
-		return 0
-	    fi
+        if [ -z "$RUN_TESTS" ]; then
+            if [ -f "$TEST/BROKEN_BUILD" ] ; then
+                dump "Skipping NDK device test not built: $TEST_NAME"
+                return 0
+            fi
+            if [ -f "$TEST/BROKEN_RUN" ] ; then
+                if [ ! -s "$TEST/BROKEN_RUN" ] ; then
+                    # skip all
+                    dump "Skipping NDK device test run: $TEST_NAME"
+                    return 0
+                else
+                    # only skip listed in file
+                    SKIPPED_EXECUTABLES=`cat $TEST/BROKEN_RUN | tr '\n' ' '`
+                    dump "Skipping NDK device test run: $TEST_NAME ($SKIPPED_EXECUTABLES)"
+                fi
+            fi
         fi
         SRCDIR="$BUILD_DIR/`basename $TEST`/libs/$CPU_ABI"
         if [ ! -d "$SRCDIR" ]; then
-            dump "Skipping NDK device test run (no $CPU_ABI binaries): `basename $TEST`"
+            dump "Skipping NDK device test run (no $CPU_ABI binaries): $TEST_NAME"
             return 0
         fi
-        # First, copy all files to the device, except for gdbserver or gdb.setup.
+        # First, copy all files to the device, except for gdbserver, gdb.setup, and
+        # those declared in $TEST/BROKEN_RUN
         adb_shell_mkdir "$DEVICE" $DSTDIR
         for SRCFILE in `ls $SRCDIR`; do
             DSTFILE=`basename $SRCFILE`
             if [ "$DSTFILE" = "gdbserver" -o "$DSTFILE" = "gdb.setup" ] ; then
                 continue
             fi
+            if [ -z "$RUN_TESTS" -a -f "$TEST/BROKEN_RUN" ]; then
+                grep -q -w -e "$DSTFILE" "$TEST/BROKEN_RUN"
+                if [ $? = 0 ] ; then
+                    continue
+                fi
+            fi
             SRCFILE="$SRCDIR/$SRCFILE"
             if [ $HOST_OS = cygwin ]; then
                 SRCFILE=`cygpath -m $SRCFILE`