merge in mnc-release history after reset to mnc-dev
diff --git a/jank/jankmicrobenchmark/Android.mk b/tests/jank/jankmicrobenchmark/Android.mk
similarity index 100%
rename from jank/jankmicrobenchmark/Android.mk
rename to tests/jank/jankmicrobenchmark/Android.mk
diff --git a/jank/jankmicrobenchmark/AndroidManifest.xml b/tests/jank/jankmicrobenchmark/AndroidManifest.xml
similarity index 100%
rename from jank/jankmicrobenchmark/AndroidManifest.xml
rename to tests/jank/jankmicrobenchmark/AndroidManifest.xml
diff --git a/jank/jankmicrobenchmark/src/com/android/jankmicrobenchmark/janktests/ApiDemoJankTests.java b/tests/jank/jankmicrobenchmark/src/com/android/jankmicrobenchmark/janktests/ApiDemoJankTests.java
similarity index 100%
rename from jank/jankmicrobenchmark/src/com/android/jankmicrobenchmark/janktests/ApiDemoJankTests.java
rename to tests/jank/jankmicrobenchmark/src/com/android/jankmicrobenchmark/janktests/ApiDemoJankTests.java
diff --git a/jank/sysapp/Android.mk b/tests/jank/sysapp/Android.mk
similarity index 100%
rename from jank/sysapp/Android.mk
rename to tests/jank/sysapp/Android.mk
diff --git a/jank/sysapp/AndroidManifest.xml b/tests/jank/sysapp/AndroidManifest.xml
similarity index 100%
rename from jank/sysapp/AndroidManifest.xml
rename to tests/jank/sysapp/AndroidManifest.xml
diff --git a/jank/sysapp/src/com/android/sysapp/janktests/BooksJankTests.java b/tests/jank/sysapp/src/com/android/sysapp/janktests/BooksJankTests.java
similarity index 100%
rename from jank/sysapp/src/com/android/sysapp/janktests/BooksJankTests.java
rename to tests/jank/sysapp/src/com/android/sysapp/janktests/BooksJankTests.java
diff --git a/jank/sysapp/src/com/android/sysapp/janktests/ChromeJankTests.java b/tests/jank/sysapp/src/com/android/sysapp/janktests/ChromeJankTests.java
similarity index 100%
rename from jank/sysapp/src/com/android/sysapp/janktests/ChromeJankTests.java
rename to tests/jank/sysapp/src/com/android/sysapp/janktests/ChromeJankTests.java
diff --git a/jank/sysapp/src/com/android/sysapp/janktests/GMailJankTests.java b/tests/jank/sysapp/src/com/android/sysapp/janktests/GMailJankTests.java
similarity index 100%
rename from jank/sysapp/src/com/android/sysapp/janktests/GMailJankTests.java
rename to tests/jank/sysapp/src/com/android/sysapp/janktests/GMailJankTests.java
diff --git a/jank/sysapp/src/com/android/sysapp/janktests/YouTubeJankTests.java b/tests/jank/sysapp/src/com/android/sysapp/janktests/YouTubeJankTests.java
similarity index 100%
rename from jank/sysapp/src/com/android/sysapp/janktests/YouTubeJankTests.java
rename to tests/jank/sysapp/src/com/android/sysapp/janktests/YouTubeJankTests.java
diff --git a/jank/webview/Android.mk b/tests/jank/webview/Android.mk
similarity index 100%
rename from jank/webview/Android.mk
rename to tests/jank/webview/Android.mk
diff --git a/jank/webview/AndroidManifest.xml b/tests/jank/webview/AndroidManifest.xml
similarity index 100%
rename from jank/webview/AndroidManifest.xml
rename to tests/jank/webview/AndroidManifest.xml
diff --git a/jank/webview/src/com/android/webview/chromium/tests/jank/WebViewFlingTest.java b/tests/jank/webview/src/com/android/webview/chromium/tests/jank/WebViewFlingTest.java
similarity index 100%
rename from jank/webview/src/com/android/webview/chromium/tests/jank/WebViewFlingTest.java
rename to tests/jank/webview/src/com/android/webview/chromium/tests/jank/WebViewFlingTest.java
diff --git a/utils/permissions/Android.mk b/utils/permissions/Android.mk
new file mode 100644
index 0000000..940f862
--- /dev/null
+++ b/utils/permissions/Android.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := PermissionUtils
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/utils/permissions/AndroidManifest.xml b/utils/permissions/AndroidManifest.xml
new file mode 100644
index 0000000..8b857d1
--- /dev/null
+++ b/utils/permissions/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2015 Google Inc.
+ *
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.permissionutils">
+
+    <uses-permission android:name="android.permission.GRANT_REVOKE_PERMISSIONS" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name=".PermissionInstrumentation"
+        android:targetPackage="com.android.permissionutils"
+        android:label="Permission Utils">
+    </instrumentation>
+</manifest>
diff --git a/utils/permissions/src/com/android/permissionutils/PermissionInstrumentation.java b/utils/permissions/src/com/android/permissionutils/PermissionInstrumentation.java
new file mode 100644
index 0000000..821c4ef
--- /dev/null
+++ b/utils/permissions/src/com/android/permissionutils/PermissionInstrumentation.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.permissionutils;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A utility to dump or grant all revoked runtime permissions
+ */
+public class PermissionInstrumentation extends Instrumentation {
+
+    private static final String DUMP_TAG = "DUMP";
+    private static final String PARAM_COMMAND = "command";
+    private static final String COMMAND_DUMP = "dump";
+    private static final String COMMAND_GRANTALL = "grant-all";
+
+    private static enum Action {DUMP, GRANTALL};
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+        String command = arguments.getString(PARAM_COMMAND);
+        if (command == null) {
+            throw new IllegalArgumentException("missing command parameter");
+        }
+        if (COMMAND_DUMP.equals(command)) {
+            runCommand(Action.DUMP);
+        } else if (COMMAND_GRANTALL.equals(command)) {
+            runCommand(Action.GRANTALL);
+        } else {
+            throw new IllegalArgumentException(
+                    String.format("unrecognized command \"%s\"", command));
+        }
+        finish(Activity.RESULT_OK, new Bundle());
+    }
+
+    private void runCommand(Action action) {
+        PackageManager pm = getContext().getPackageManager();
+        List<PackageInfo> pkgInfos = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
+        List<String> permissions = new ArrayList<>();
+        for (PackageInfo info : pkgInfos) {
+            if (info.requestedPermissions == null) {
+                continue;
+            }
+            for (String permission : info.requestedPermissions) {
+                PermissionInfo pi = null;
+                try {
+                    pi = pm.getPermissionInfo(permission, 0);
+                } catch (NameNotFoundException nnfe) {
+                    // ignore
+                }
+                if (pi == null) {
+                    continue;
+                }
+                if (!isRuntime(pi)) {
+                    continue;
+                }
+                int flag = pm.checkPermission(permission, info.packageName);
+                if (flag == PackageManager.PERMISSION_DENIED) {
+                    if (action == Action.DUMP) {
+                        permissions.add(permission);
+                    } else if (action == Action.GRANTALL) {
+                        pm.grantRuntimePermission(info.packageName, permission, UserHandle.OWNER);
+                    }
+                }
+            }
+            if (action == Action.DUMP && !permissions.isEmpty()) {
+                Log.e(DUMP_TAG, String.format("Revoked permissions for %s", info.packageName));
+                for (String permission : permissions) {
+                    Log.e(DUMP_TAG, "    " + permission);
+                }
+                permissions.clear();
+            }
+        }
+    }
+
+    private boolean isRuntime(PermissionInfo pi) {
+        return (pi.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+                == PermissionInfo.PROTECTION_DANGEROUS;
+    }
+}