Adding a few host-based stress tests for Apps on SD.

Change-Id: I0ccb1f3574688f60b6296dac6f6859ba5d0597ea
diff --git a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java
index 8dfa850..2326672 100644
--- a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java
+++ b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import com.android.ddmlib.AndroidDebugBridge;
 import com.android.ddmlib.IDevice;
 import com.android.ddmlib.IShellOutputReceiver;
 import com.android.ddmlib.Log;
@@ -23,11 +24,21 @@
 import com.android.ddmlib.SyncService;
 import com.android.ddmlib.SyncService.ISyncProgressMonitor;
 import com.android.ddmlib.SyncService.SyncResult;
+import com.android.ddmlib.testrunner.ITestRunListener;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.hosttest.DeviceTestCase;
 import com.android.hosttest.DeviceTestSuite;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.InputStreamReader;
 import java.io.IOException;
+import java.io.StringReader;
+import java.lang.Runtime;
+import java.lang.Process;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import junit.framework.Assert;
 import com.android.hosttest.DeviceTestCase;
@@ -47,6 +58,21 @@
 
     private static final int MAX_WAIT_FOR_DEVICE_TIME = 120 * 1000;
     private static final int WAIT_FOR_DEVICE_POLL_TIME = 10 * 1000;
+    private static final int MAX_WAIT_FOR_APP_LAUNCH_TIME = 60 * 1000;
+    private static final int WAIT_FOR_APP_LAUNCH_POLL_TIME = 5 * 1000;
+
+    // Install preference on the device-side
+    public static enum InstallLocPreference {
+        AUTO,
+        INTERNAL,
+        EXTERNAL
+    }
+
+    // Actual install location
+    public static enum InstallLocation {
+        DEVICE,
+        SDCARD
+    }
 
     /**
      * Constructor takes the device to use
@@ -90,6 +116,30 @@
     }
 
     /**
+     * Helper method to run tests and return the listener that collected the results.
+     * @param pkgName Android application package for tests
+     * @return the {@link CollectingTestRunListener}
+     */
+    private CollectingTestRunListener doRunTests(String pkgName) {
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
+                pkgName, mDevice);
+        CollectingTestRunListener listener = new CollectingTestRunListener();
+        testRunner.run(listener);
+        return listener;
+    }
+
+    /**
+     * Runs the specified packages tests, and returns whether all tests passed or not.
+     *
+     * @param pkgName Android application package for tests
+     * @return true if every test passed, false otherwise.
+     */
+    public boolean runDeviceTestsDidAllTestsPass(String pkgName) {
+        CollectingTestRunListener listener = doRunTests(pkgName);
+        return listener.didAllTestsPass();
+    }
+
+    /**
      * Helper method to push a file to device
      * @param apkAppPrivatePath
      * @throws IOException
@@ -102,18 +152,48 @@
     }
 
     /**
-     * Helper method to install a file to device
+     * Helper method to install a file
      * @param localFilePath the absolute file system path to file on local host to install
      * @param reinstall set to <code>true</code> if re-install of app should be performed
      * @throws IOException
      */
-    public void installFile(final String localFilePath, final boolean replace)
-            throws IOException {
+    public void installFile(final String localFilePath, final boolean replace) throws IOException {
         String result = mDevice.installPackage(localFilePath, replace);
         assertEquals(null, result);
     }
 
     /**
+     * Helper method to install a file that should not be install-able
+     * @param localFilePath the absolute file system path to file on local host to install
+     * @param reinstall set to <code>true</code> if re-install of app should be performed
+     * @return the string output of the failed install attempt
+     * @throws IOException
+     */
+    public String installFileFail(final String localFilePath, final boolean replace)
+            throws IOException {
+        String result = mDevice.installPackage(localFilePath, replace);
+        assertNotNull(result);
+        return result;
+    }
+
+    /**
+     * Helper method to install a file to device as forward locked
+     * @param localFilePath the absolute file system path to file on local host to install
+     * @param reinstall set to <code>true</code> if re-install of app should be performed
+     * @throws IOException
+     */
+    public String installFileForwardLocked(final String localFilePath, final boolean replace)
+            throws IOException {
+        String remoteFilePath = mDevice.syncPackageToDevice(localFilePath);
+        InstallReceiver receiver = new InstallReceiver();
+        String cmd = String.format(replace ? "pm install -r -l \"%1$s\"" :
+                "pm install -l \"%1$s\"", remoteFilePath);
+        mDevice.executeShellCommand(cmd, receiver);
+        mDevice.removeRemotePackage(remoteFilePath);
+        return receiver.getErrorMessage();
+    }
+
+    /**
      * Helper method to determine if file on device exists.
      *
      * @param destPath the absolute path of file on device to check
@@ -128,7 +208,7 @@
     /**
      * Helper method to determine if file exists on the device containing a given string.
      *
-     * @param destPath the
+     * @param destPath the absolute path of the file
      * @return <code>true</code> if file exists containing given string,
      *         <code>false</code> otherwise.
      * @throws IOException if adb shell command failed
@@ -152,18 +232,18 @@
     }
 
     /**
-     * Helper method to determine if app was installed on device.
+     * Determines if app was installed on device.
      *
      * @param packageName package name to check for
      * @return <code>true</code> if file exists, <code>false</code> otherwise.
      * @throws IOException if adb shell command failed
      */
-    private boolean doesAppExistOnDevice(String packageName) throws IOException {
+    public boolean doesAppExistOnDevice(String packageName) throws IOException {
         return doesRemoteFileExistContainingString(DEVICE_APP_PATH, packageName);
     }
 
     /**
-     * Helper method to determine if app was installed on SD card.
+     * Determines if app was installed on SD card.
      *
      * @param packageName package name to check for
      * @return <code>true</code> if file exists, <code>false</code> otherwise.
@@ -174,12 +254,23 @@
     }
 
     /**
+     * Helper method to determine if app was installed on SD card.
+     *
+     * @param packageName package name to check for
+     * @return <code>true</code> if file exists, <code>false</code> otherwise.
+     * @throws IOException if adb shell command failed
+     */
+    public boolean doesAppExistAsForwardLocked(String packageName) throws IOException {
+        return doesRemoteFileExistContainingString(APP_PRIVATE_PATH, packageName);
+    }
+
+    /**
      * Waits for device's package manager to respond.
      *
      * @throws InterruptedException
      * @throws IOException
      */
-    public void waitForDevice() throws InterruptedException, IOException {
+    public void waitForPackageManager() throws InterruptedException, IOException {
         Log.i(LOG_TAG, "waiting for device");
         int currentWaitTime = 0;
         // poll the package manager until it returns something for android
@@ -194,20 +285,125 @@
     }
 
     /**
+     * Helper to determine if the device is currently online and visible via ADB.
+     *
+     * @return true iff the device is currently available to ADB and online, false otherwise.
+     */
+    private boolean deviceIsOnline() {
+        AndroidDebugBridge bridge = AndroidDebugBridge.getBridge();
+        IDevice[] devices = bridge.getDevices();
+
+        for (IDevice device : devices) {
+            // only online if the device appears in the devices list, and its state is online
+            if ((mDevice != null) &&
+                    mDevice.getSerialNumber().equals(device.getSerialNumber()) &&
+                    device.isOnline()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Waits for device to be online (visible to ADB) before returning, or times out if we've
+     * waited too long. Note that this only means the device is visible via ADB, not that
+     * PackageManager is fully up and running yet.
+     *
+     * @throws InterruptedException
+     * @throws IOException
+     */
+    public void waitForDeviceToComeOnline() throws InterruptedException, IOException {
+        Log.i(LOG_TAG, "waiting for device to be online");
+        int currentWaitTime = 0;
+
+        // poll ADB until we see the device is online
+        while (!deviceIsOnline()) {
+            Thread.sleep(WAIT_FOR_DEVICE_POLL_TIME);
+            currentWaitTime += WAIT_FOR_DEVICE_POLL_TIME;
+            if (currentWaitTime > MAX_WAIT_FOR_DEVICE_TIME) {
+                Log.e(LOG_TAG, "time out waiting for device");
+                throw new InterruptedException();
+            }
+        }
+        // Note: if we try to access the device too quickly after it is "officially" online,
+        // there are sometimes strange issues where it's actually not quite ready yet,
+        // so we pause for a bit once more before actually returning.
+        Thread.sleep(WAIT_FOR_DEVICE_POLL_TIME);
+    }
+
+    /**
+     * Queries package manager and waits until a package is launched (or times out)
+     *
+     * @param packageName The name of the package to wait to load
+     * @throws InterruptedException
+     * @throws IOException
+     */
+    public void waitForApp(String packageName) throws InterruptedException, IOException {
+        Log.i(LOG_TAG, "waiting for app to launch");
+        int currentWaitTime = 0;
+        // poll the package manager until it returns something for the package we're looking for
+        while (!doesPackageExist(packageName)) {
+            Thread.sleep(WAIT_FOR_APP_LAUNCH_POLL_TIME);
+            currentWaitTime += WAIT_FOR_APP_LAUNCH_POLL_TIME;
+            if (currentWaitTime > MAX_WAIT_FOR_APP_LAUNCH_TIME) {
+                Log.e(LOG_TAG, "time out waiting for app to launch: " + packageName);
+                throw new InterruptedException();
+            }
+        }
+    }
+
+    /**
      * Helper method which executes a adb shell command and returns output as a {@link String}
      * @return the output of the command
      * @throws IOException
      */
     public String executeShellCommand(String command) throws IOException {
-        Log.d(LOG_TAG, String.format("adb shell %s", command));
+        Log.i(LOG_TAG, String.format("adb shell %s", command));
         CollectingOutputReceiver receiver = new CollectingOutputReceiver();
         mDevice.executeShellCommand(command, receiver);
         String output = receiver.getOutput();
-        Log.d(LOG_TAG, String.format("Result: %s", output));
+        Log.i(LOG_TAG, String.format("Result: %s", output));
         return output;
     }
 
     /**
+     * Helper method ensures we are in root mode on the host side. It returns only after
+     * PackageManager is actually up and running.
+     * @throws IOException
+     */
+    public void runAdbRoot() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "adb root");
+        Runtime runtime = Runtime.getRuntime();
+        Process process = runtime.exec("adb root"); // adb should be in the path
+        BufferedReader output = new BufferedReader(new InputStreamReader(process.getInputStream()));
+
+        String nextLine = null;
+        while (null != (nextLine = output.readLine())) {
+            Log.i(LOG_TAG, nextLine);
+        }
+        process.waitFor();
+        waitForDeviceToComeOnline();
+        waitForPackageManager(); // now wait for package manager to actually load
+    }
+
+    /**
+     * Helper method which reboots the device and returns once the device is online again
+     * and package manager is up and running (note this function is synchronous to callers).
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    public void rebootDevice() throws IOException, InterruptedException {
+        String command = "reboot"; // no need for -s since mDevice is already tied to a device
+        Log.i(LOG_TAG, command);
+        CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+        mDevice.executeShellCommand(command, receiver);
+        String output = receiver.getOutput();
+        Log.i(LOG_TAG, String.format("Result: %s", output));
+        waitForDeviceToComeOnline(); // wait for device to come online
+        runAdbRoot();
+    }
+
+    /**
      * A {@link IShellOutputReceiver} which collects the whole shell output into one {@link String}
      */
     private class CollectingOutputReceiver extends MultiLineReceiver {
@@ -255,6 +451,97 @@
         }
     }
 
+    // For collecting results from running device tests
+    private static class CollectingTestRunListener implements ITestRunListener {
+
+        private boolean mAllTestsPassed = true;
+        private String mTestRunErrorMessage = null;
+
+        public void testEnded(TestIdentifier test) {
+            // ignore
+        }
+
+        public void testFailed(TestFailure status, TestIdentifier test,
+                String trace) {
+            Log.w(LOG_TAG, String.format("%s#%s failed: %s", test.getClassName(),
+                    test.getTestName(), trace));
+            mAllTestsPassed = false;
+        }
+
+        public void testRunEnded(long elapsedTime) {
+            // ignore
+        }
+
+        public void testRunFailed(String errorMessage) {
+            Log.w(LOG_TAG, String.format("test run failed: %s", errorMessage));
+            mAllTestsPassed = false;
+            mTestRunErrorMessage = errorMessage;
+        }
+
+        public void testRunStarted(int testCount) {
+            // ignore
+        }
+
+        public void testRunStopped(long elapsedTime) {
+            // ignore
+        }
+
+        public void testStarted(TestIdentifier test) {
+            // ignore
+        }
+
+        boolean didAllTestsPass() {
+            return mAllTestsPassed;
+        }
+
+        /**
+         * Get the test run failure error message.
+         * @return the test run failure error message or <code>null</code> if test run completed.
+         */
+        String getTestRunErrorMessage() {
+            return mTestRunErrorMessage;
+        }
+    }
+
+    /**
+     * Output receiver for "pm install package.apk" command line.
+     *
+     */
+    private static final class InstallReceiver extends MultiLineReceiver {
+
+        private static final String SUCCESS_OUTPUT = "Success"; //$NON-NLS-1$
+        private static final Pattern FAILURE_PATTERN = Pattern.compile("Failure\\s+\\[(.*)\\]"); //$NON-NLS-1$
+
+        private String mErrorMessage = null;
+
+        public InstallReceiver() {
+        }
+
+        @Override
+        public void processNewLines(String[] lines) {
+            for (String line : lines) {
+                if (line.length() > 0) {
+                    if (line.startsWith(SUCCESS_OUTPUT)) {
+                        mErrorMessage = null;
+                    } else {
+                        Matcher m = FAILURE_PATTERN.matcher(line);
+                        if (m.matches()) {
+                            mErrorMessage = m.group(1);
+                        }
+                    }
+                }
+            }
+        }
+
+        public boolean isCancelled() {
+            return false;
+        }
+
+        public String getErrorMessage() {
+            return mErrorMessage;
+        }
+    }
+
     /**
      * Helper method for installing an app to wherever is specified in its manifest, and
      * then verifying the app was installed onto SD Card.
@@ -280,7 +567,7 @@
         installFile(apkPath, overwrite);
         assertTrue(doesAppExistOnSDCard(pkgName));
         assertFalse(doesAppExistOnDevice(pkgName));
-        waitForDevice();
+        waitForPackageManager();
 
         // grep for package to make sure it is installed
         assertTrue(doesPackageExist(pkgName));
@@ -311,7 +598,39 @@
         installFile(apkPath, overwrite);
         assertFalse(doesAppExistOnSDCard(pkgName));
         assertTrue(doesAppExistOnDevice(pkgName));
-        waitForDevice();
+        waitForPackageManager();
+
+        // grep for package to make sure it is installed
+        assertTrue(doesPackageExist(pkgName));
+    }
+
+    /**
+     * Helper method for installing an app as forward-locked, and
+     * then verifying the app was installed in the proper forward-locked location.
+     *
+     * @param the path of the apk to install
+     * @param the name of the package
+     * @param <code>true</code> if the app should be overwritten, <code>false</code> otherwise
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void installFwdLockedAppAndVerifyExists(String apkPath,
+            String pkgName, boolean overwrite) throws IOException, InterruptedException {
+        // Start with a clean slate if we're not overwriting
+        if (!overwrite) {
+            // cleanup test app just in case it already exists
+            mDevice.uninstallPackage(pkgName);
+            // grep for package to make sure its not installed
+            assertFalse(doesPackageExist(pkgName));
+        }
+
+        String result = installFileForwardLocked(apkPath, overwrite);
+        assertEquals(null, result);
+        assertTrue(doesAppExistAsForwardLocked(pkgName));
+        assertFalse(doesAppExistOnSDCard(pkgName));
+        waitForPackageManager();
 
         // grep for package to make sure it is installed
         assertTrue(doesPackageExist(pkgName));
@@ -332,4 +651,74 @@
         assertFalse(doesPackageExist(pkgName));
     }
 
+    /**
+     * Helper method for clearing any installed non-system apps.
+     * Useful ensuring no non-system apps are installed, and for cleaning up stale files that
+     * may be lingering on the system for whatever reason.
+     *
+     * @throws IOException if adb shell command failed
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void wipeNonSystemApps() throws IOException {
+      String allInstalledPackages = executeShellCommand("pm list packages -f");
+      BufferedReader outputReader = new BufferedReader(new StringReader(allInstalledPackages));
+
+      // First use Package Manager to uninstall all non-system apps
+      String currentLine = null;
+      while ((currentLine = outputReader.readLine()) != null) {
+          // Skip over any system apps...
+          if (currentLine.contains("/system/")) {
+              continue;
+          }
+          String packageName = currentLine.substring(currentLine.indexOf('=') + 1);
+          mDevice.uninstallPackage(packageName);
+      }
+      // Make sure there are no stale app files under these directories
+      executeShellCommand(String.format("rm %s*", SDCARD_APP_PATH, "*"));
+      executeShellCommand(String.format("rm %s*", DEVICE_APP_PATH, "*"));
+      executeShellCommand(String.format("rm %s*", APP_PRIVATE_PATH, "*"));
+    }
+
+    /**
+     * Sets the device's install location preference.
+     *
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void setDevicePreferredInstallLocation(InstallLocPreference pref) throws IOException {
+        String command = "pm setInstallLocation %d";
+        int locValue = 0;
+        switch (pref) {
+            case INTERNAL:
+                locValue = 1;
+                break;
+            case EXTERNAL:
+                locValue = 2;
+                break;
+            default: // AUTO
+                locValue = 0;
+                break;
+        }
+        executeShellCommand(String.format(command, locValue));
+    }
+
+    /**
+     * Gets the device's install location preference.
+     *
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public InstallLocPreference getDevicePreferredInstallLocation() throws IOException {
+        String result = executeShellCommand("pm getInstallLocation");
+        if (result.indexOf('0') != -1) {
+            return InstallLocPreference.AUTO;
+        }
+        else if (result.indexOf('1') != -1) {
+            return InstallLocPreference.INTERNAL;
+        }
+        else {
+            return InstallLocPreference.EXTERNAL;
+        }
+    }
 }
diff --git a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java
index 90ddc3a..1b797d5 100644
--- a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java
+++ b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java
@@ -59,6 +59,21 @@
     // Apk with install location set to preferExternal
     private static final String EXTERNAL_LOC_APK = "ExternalLocTestApp.apk";
     private static final String EXTERNAL_LOC_PKG = "com.android.framework.externalloctestapp";
+    // Apk with install location set to auto (2 versions, for update testing)
+    private static final String AUTO_LOC_VERSION_V1_APK = "AutoLocVersionedTestApp_v1.apk";
+    private static final String AUTO_LOC_VERSION_V2_APK = "AutoLocVersionedTestApp_v2.apk";
+    private static final String AUTO_LOC_VERSION_PKG =
+            "com.android.framework.autolocversionedtestapp";
+    // Apk with install location set to preferExternal (2 versions, for update testing)
+    private static final String EXTERNAL_LOC_VERSION_V1_APK = "ExternalLocVersionedTestApp_v1.apk";
+    private static final String EXTERNAL_LOC_VERSION_V2_APK = "ExternalLocVersionedTestApp_v2.apk";
+    private static final String EXTERNAL_LOC_VERSION_PKG =
+            "com.android.framework.externallocversionedtestapp";
+    // Apk with install location set to auto (2 versions, for update testing)
+    private static final String NO_LOC_VERSION_V1_APK = "NoLocVersionedTestApp_v1.apk";
+    private static final String NO_LOC_VERSION_V2_APK = "NoLocVersionedTestApp_v2.apk";
+    private static final String NO_LOC_VERSION_PKG =
+            "com.android.framework.nolocversionedtestapp";
     // Apk with no install location set
     private static final String NO_LOC_APK = "NoLocTestApp.apk";
     private static final String NO_LOC_PKG = "com.android.framework.noloctestapp";
@@ -76,6 +91,12 @@
             = "UpdateExtToIntLocTestApp_v2_int.apk";
     private static final String UPDATE_EXT_TO_INT_LOC_PKG
             = "com.android.framework.updateexttointloctestapp";
+    // Apk set to preferExternal, with Access Fine Location permissions set in its manifest
+    private static final String FL_PERMS_APK = "ExternalLocPermsFLTestApp.apk";
+    private static final String FL_PERMS_PKG = "com.android.framework.externallocpermsfltestapp";
+    // Apk set to preferExternal, with all permissions set in manifest
+    private static final String ALL_PERMS_APK = "ExternalLocAllPermsTestApp.apk";
+    private static final String ALL_PERMS_PKG = "com.android.framework.externallocallpermstestapp";
     // Apks with the same package name, but install location set to
     // one of: Internal, External, Auto, or None
     private static final String VERSATILE_LOC_PKG = "com.android.framework.versatiletestapp";
@@ -83,6 +104,20 @@
     private static final String VERSATILE_LOC_EXTERNAL_APK = "VersatileTestApp_External.apk";
     private static final String VERSATILE_LOC_AUTO_APK = "VersatileTestApp_Auto.apk";
     private static final String VERSATILE_LOC_NONE_APK = "VersatileTestApp_None.apk";
+    // Apks with shared UserID
+    private static final String SHARED_PERMS_APK = "ExternalSharedPermsTestApp.apk";
+    private static final String SHARED_PERMS_PKG
+            = "com.android.framework.externalsharedpermstestapp";
+    private static final String SHARED_PERMS_FL_APK = "ExternalSharedPermsFLTestApp.apk";
+    private static final String SHARED_PERMS_FL_PKG
+            = "com.android.framework.externalsharedpermsfltestapp";
+    private static final String SHARED_PERMS_BT_APK = "ExternalSharedPermsBTTestApp.apk";
+    private static final String SHARED_PERMS_BT_PKG
+            = "com.android.framework.externalsharedpermsbttestapp";
+    // Apk with shared UserID, but signed with a different cert (the media cert)
+    private static final String SHARED_PERMS_DIFF_KEY_APK = "ExternalSharedPermsDiffKeyTestApp.apk";
+    private static final String SHARED_PERMS_DIFF_KEY_PKG
+            = "com.android.framework.externalsharedpermsdiffkeytestapp";
 
     @Override
     protected void setUp() throws Exception {
@@ -95,6 +130,12 @@
         appPrivatePath = mPMHostUtils.getAppPrivatePath();
         deviceAppPath = mPMHostUtils.getDeviceAppPath();
         sdcardAppPath = mPMHostUtils.getSDCardAppPath();
+
+        // Ensure the default is set to let the system decide where to install apps
+        // (It's ok for individual tests to override and change this during their test, but should
+        // reset it back when they're done)
+        mPMHostUtils.setDevicePreferredInstallLocation(
+                PackageManagerHostTestUtils.InstallLocPreference.AUTO);
     }
 
     /**
@@ -115,6 +156,8 @@
      * the app, and otherwise cause the system to blow up.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
     public void testPushAppPrivate() throws IOException, InterruptedException {
         Log.i(LOG_TAG, "testing pushing an apk to /data/app-private");
@@ -129,7 +172,7 @@
         assertTrue(mPMHostUtils.doesRemoteFileExist(apkAppPrivatePath));
         mPMHostUtils.executeShellCommand("start");
 
-        mPMHostUtils.waitForDevice();
+        mPMHostUtils.waitForPackageManager();
 
         // grep for package to make sure its not installed
         assertFalse(mPMHostUtils.doesPackageExist(SIMPLE_PKG));
@@ -138,35 +181,346 @@
     }
 
     /**
-     * Regression test to verify that an app with its manifest set to installLocation=auto
-     * will install the app to the device.
+     * Helper to do a standard install of an apk and verify it installed to the correct location.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @param apkName the file name of the test app apk
+     * @param pkgName the package name of the test app apk
+     * @param expectedLocation the file name of the test app apk
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
-    public void testInstallAppAutoLoc() throws IOException, InterruptedException {
-        Log.i(LOG_TAG, "Test an app with installLocation=auto gets installed on device");
+    private void doStandardInstall(String apkName, String pkgName,
+            PackageManagerHostTestUtils.InstallLocation expectedLocation)
+            throws IOException, InterruptedException {
+
+        if (expectedLocation == PackageManagerHostTestUtils.InstallLocation.DEVICE) {
+            mPMHostUtils.installAppAndVerifyExistsOnDevice(
+                    getTestAppFilePath(apkName), pkgName, false);
+        }
+        else {
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(
+                    getTestAppFilePath(apkName), pkgName, false);
+        }
+    }
+
+    /**
+     * Installs the Auto app using the preferred device install location specified,
+     * and verifies it was installed on the device.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @param preference the device's preferred location of where to install apps
+     * @param expectedLocation the expected location of where the apk was installed
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void installAppAutoLoc(PackageManagerHostTestUtils.InstallLocPreference preference,
+            PackageManagerHostTestUtils.InstallLocation expectedLocation)
+            throws IOException, InterruptedException {
+
+        PackageManagerHostTestUtils.InstallLocPreference savedPref =
+                PackageManagerHostTestUtils.InstallLocPreference.AUTO;
 
         try {
-            mPMHostUtils.installAppAndVerifyExistsOnDevice(
-                    getTestAppFilePath(AUTO_LOC_APK), AUTO_LOC_PKG, false);
+            savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
+            mPMHostUtils.setDevicePreferredInstallLocation(preference);
+
+            doStandardInstall(AUTO_LOC_APK, AUTO_LOC_PKG, expectedLocation);
         }
         // cleanup test app
         finally {
+            mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
             mPMHostUtils.uninstallApp(AUTO_LOC_PKG);
         }
     }
 
     /**
-     * Regression test to verify that an app with its manifest set to installLocation=internalOnly
-     * will install the app to the device.
+     * Regression test to verify that an app with its manifest set to installLocation=auto
+     * will install the app to the device when device's preference is auto.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
-    public void testInstallAppInternalLoc() throws IOException, InterruptedException {
-        Log.i(LOG_TAG, "Test an app with installLocation=internalOnly gets installed on device");
+    public void testInstallAppAutoLocPrefIsAuto() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=auto, prefer=auto gets installed on device");
+        installAppAutoLoc(PackageManagerHostTestUtils.InstallLocPreference.AUTO,
+                PackageManagerHostTestUtils.InstallLocation.DEVICE);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=auto
+     * will install the app to the device when device's preference is internal.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppAutoLocPrefIsInternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=auto, prefer=internal gets installed on device");
+        installAppAutoLoc(PackageManagerHostTestUtils.InstallLocPreference.INTERNAL,
+                PackageManagerHostTestUtils.InstallLocation.DEVICE);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=auto
+     * will install the app to the SD card when device's preference is external.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppAutoLocPrefIsExternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=auto, prefer=external gets installed on device");
+        installAppAutoLoc(PackageManagerHostTestUtils.InstallLocPreference.EXTERNAL,
+                PackageManagerHostTestUtils.InstallLocation.DEVICE);
+    }
+
+    /**
+     * Installs the Internal app using the preferred device install location specified,
+     * and verifies it was installed to the location expected.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @param preference the device's preferred location of where to install apps
+     * @param expectedLocation the expected location of where the apk was installed
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void installAppInternalLoc(PackageManagerHostTestUtils.InstallLocPreference preference,
+            PackageManagerHostTestUtils.InstallLocation expectedLocation)
+            throws IOException, InterruptedException {
+
+        PackageManagerHostTestUtils.InstallLocPreference savedPref =
+            PackageManagerHostTestUtils.InstallLocPreference.AUTO;
 
         try {
+            savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
+            mPMHostUtils.setDevicePreferredInstallLocation(preference);
+
+            doStandardInstall(INTERNAL_LOC_APK, INTERNAL_LOC_PKG, expectedLocation);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
+            mPMHostUtils.uninstallApp(INTERNAL_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=internalOnly
+     * will install the app to the device when device's preference is auto.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppInternalLocPrefIsAuto() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=internal, prefer=auto gets installed on device");
+        installAppInternalLoc(PackageManagerHostTestUtils.InstallLocPreference.AUTO,
+                PackageManagerHostTestUtils.InstallLocation.DEVICE);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=internalOnly
+     * will install the app to the device when device's preference is internal.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppInternalLocPrefIsInternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=internal, prefer=internal is installed on device");
+        installAppInternalLoc(PackageManagerHostTestUtils.InstallLocPreference.INTERNAL,
+                PackageManagerHostTestUtils.InstallLocation.DEVICE);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=internalOnly
+     * will install the app to the device when device's preference is external.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppInternalLocPrefIsExternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=internal, prefer=external is installed on device");
+        installAppInternalLoc(PackageManagerHostTestUtils.InstallLocPreference.EXTERNAL,
+                PackageManagerHostTestUtils.InstallLocation.DEVICE);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=preferExternal
+     * will install the app to the SD card.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @param preference the device's preferred location of where to install apps
+     * @param expectedLocation the expected location of where the apk was installed
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void installAppExternalLoc(PackageManagerHostTestUtils.InstallLocPreference preference,
+            PackageManagerHostTestUtils.InstallLocation expectedLocation)
+            throws IOException, InterruptedException {
+
+        PackageManagerHostTestUtils.InstallLocPreference savedPref =
+            PackageManagerHostTestUtils.InstallLocPreference.AUTO;
+
+        try {
+            savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
+            mPMHostUtils.setDevicePreferredInstallLocation(preference);
+
+            doStandardInstall(EXTERNAL_LOC_APK, EXTERNAL_LOC_PKG, expectedLocation);
+
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
+            mPMHostUtils.uninstallApp(EXTERNAL_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=preferExternal
+     * will install the app to the device when device's preference is auto.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppExternalLocPrefIsAuto() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=external, pref=auto gets installed on SD Card");
+        installAppExternalLoc(PackageManagerHostTestUtils.InstallLocPreference.AUTO,
+                PackageManagerHostTestUtils.InstallLocation.SDCARD);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=preferExternal
+     * will install the app to the device when device's preference is internal.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppExternalLocPrefIsInternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=external, pref=internal gets installed on SD Card");
+        installAppExternalLoc(PackageManagerHostTestUtils.InstallLocPreference.INTERNAL,
+                PackageManagerHostTestUtils.InstallLocation.SDCARD);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=preferExternal
+     * will install the app to the device when device's preference is external.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppExternalLocPrefIsExternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=external, pref=external gets installed on SD Card");
+        installAppExternalLoc(PackageManagerHostTestUtils.InstallLocPreference.EXTERNAL,
+                PackageManagerHostTestUtils.InstallLocation.SDCARD);
+    }
+
+    /**
+     * Regression test to verify that an app without installLocation in its manifest
+     * will install the app to the device by default when the system default pref is to let the
+     * system decide.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppNoLocPrefIsAuto() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with no installLocation gets installed on device");
+
+        PackageManagerHostTestUtils.InstallLocPreference savedPref =
+            PackageManagerHostTestUtils.InstallLocPreference.AUTO;
+
+        try {
+            savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
+            mPMHostUtils.setDevicePreferredInstallLocation(
+                    PackageManagerHostTestUtils.InstallLocPreference.AUTO);
             mPMHostUtils.installAppAndVerifyExistsOnDevice(
+                    getTestAppFilePath(NO_LOC_APK), NO_LOC_PKG, false);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
+            mPMHostUtils.uninstallApp(NO_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app without installLocation in its manifest
+     * will install the app to the device by default when the system default pref is to install
+     * external.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppNoLocPrefIsExternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with no installLocation gets installed on SD card");
+
+        PackageManagerHostTestUtils.InstallLocPreference savedPref =
+            PackageManagerHostTestUtils.InstallLocPreference.AUTO;
+
+        try {
+            savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
+            mPMHostUtils.setDevicePreferredInstallLocation(
+                    PackageManagerHostTestUtils.InstallLocPreference.EXTERNAL);
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(
+                    getTestAppFilePath(NO_LOC_APK), NO_LOC_PKG, false);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
+            mPMHostUtils.uninstallApp(NO_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app without installLocation in its manifest
+     * will install the app to the device by default when the system default pref is to install
+     * internal.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppNoLocPrefIsInternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with no installLocation gets installed on device");
+
+        PackageManagerHostTestUtils.InstallLocPreference savedPref =
+            PackageManagerHostTestUtils.InstallLocPreference.AUTO;
+
+        try {
+            savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
+            mPMHostUtils.setDevicePreferredInstallLocation(
+                    PackageManagerHostTestUtils.InstallLocPreference.INTERNAL);
+            mPMHostUtils.installAppAndVerifyExistsOnDevice(
+                    getTestAppFilePath(NO_LOC_APK), NO_LOC_PKG, false);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
+            mPMHostUtils.uninstallApp(NO_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with its installLocation set to internal that is
+     * forward-locked will get installed to the correct location.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallFwdLockedAppInternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with installLoc set to Internal gets installed to app-private");
+
+        try {
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(
                     getTestAppFilePath(INTERNAL_LOC_APK), INTERNAL_LOC_PKG, false);
         }
         // cleanup test app
@@ -176,21 +530,65 @@
     }
 
     /**
-     * Regression test to verify that an app with its manifest set to installLocation=preferExternal
-     * will install the app to the SD card.
+     * Regression test to verify that an app with its installLocation set to external that is
+     * forward-locked will get installed to the correct location.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
-    public void testInstallAppExternalLoc() throws IOException, InterruptedException {
-        Log.i(LOG_TAG, "Test an app with installLocation=preferExternal gets installed on SD Card");
+    public void testInstallFwdLockedAppExternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with installLoc set to Internal gets installed to app-private");
 
         try {
-            mPMHostUtils.installAppAndVerifyExistsOnSDCard(
-                    getTestAppFilePath(EXTERNAL_LOC_APK), EXTERNAL_LOC_PKG, false);
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(
+                    getTestAppFilePath(INTERNAL_LOC_APK), INTERNAL_LOC_PKG, false);
         }
         // cleanup test app
         finally {
-            mPMHostUtils.uninstallApp(EXTERNAL_LOC_PKG);
+            mPMHostUtils.uninstallApp(INTERNAL_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with its installLocation set to external that is
+     * forward-locked will get installed to the correct location.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallFwdLockedAppAuto() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with installLoc set to Auto gets installed to app-private");
+
+        try {
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(
+                    getTestAppFilePath(AUTO_LOC_APK), AUTO_LOC_PKG, false);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(AUTO_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with no installLocation set and is
+     * forward-locked installed will get installed to the correct location.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallFwdLockedAppNone() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with no installLoc set gets installed to app-private");
+
+        try {
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(
+                    getTestAppFilePath(NO_LOC_APK), NO_LOC_PKG, false);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(NO_LOC_PKG);
         }
     }
 
@@ -199,6 +597,8 @@
      * uninstall it, and reinstall it onto the SD card.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
     // TODO: This currently relies on the app's manifest to switch from device to
     // SD card install locations. We might want to make Device's installPackage()
@@ -225,6 +625,8 @@
      * uninstall it, and reinstall it onto the device.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
     // TODO: This currently relies on the app's manifest to switch from device to
     // SD card install locations. We might want to make Device's installPackage()
@@ -250,10 +652,37 @@
 
     /**
      * Regression test to verify that updating an app on the SD card will install
+     * the update onto the SD card as well when location is set to external for both versions
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testUpdateBothExternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test updating an app on the SD card stays on the SD card");
+
+        try {
+            // install the app externally
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    EXTERNAL_LOC_VERSION_V1_APK), EXTERNAL_LOC_VERSION_PKG, false);
+            // now replace the app with one where the location is still set to preferExternal
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    EXTERNAL_LOC_VERSION_V2_APK), EXTERNAL_LOC_VERSION_PKG, true);
+        }
+        // cleanup test app
+        finally {
+          mPMHostUtils.uninstallApp(EXTERNAL_LOC_VERSION_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that updating an app on the SD card will install
      * the update onto the SD card as well when location is not explicitly set in the
      * updated apps' manifest file.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
     public void testUpdateToSDCard() throws IOException, InterruptedException {
         Log.i(LOG_TAG, "Test updating an app on the SD card stays on the SD card");
@@ -274,10 +703,11 @@
 
     /**
      * Regression test to verify that updating an app on the SD card will install
-     * the update onto the SD card as well when location is not explicitly set in the
-     * updated apps' manifest file.
+     * the update onto the device if the manifest has changed to installLocation=internalOnly
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
     public void testUpdateSDCardToDevice() throws IOException, InterruptedException {
         Log.i(LOG_TAG, "Test updating an app on the SD card to the Device through manifest change");
@@ -286,7 +716,7 @@
             // install the app externally
             mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
                     UPDATE_EXT_TO_INT_LOC_V1_EXT_APK), UPDATE_EXT_TO_INT_LOC_PKG, false);
-            // now replace the app with an update marked for internalOnly...
+            // now replace the app with an update marked for internalOnly...(should move internal)
             mPMHostUtils.installAppAndVerifyExistsOnDevice(getTestAppFilePath(
                     UPDATE_EXT_TO_INT_LOC_V2_INT_APK), UPDATE_EXT_TO_INT_LOC_PKG, true);
         }
@@ -295,4 +725,264 @@
             mPMHostUtils.uninstallApp(UPDATE_EXT_TO_INT_LOC_PKG);
         }
     }
+
+    /**
+     * Regression test to verify that installing and updating a forward-locked app will install
+     * the update onto the device's forward-locked location
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndUpdateExternalLocForwardLockedApp()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test updating a forward-locked app marked preferExternal");
+
+        try {
+            // first try to install the forward-locked app externally
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(getTestAppFilePath(
+                    EXTERNAL_LOC_VERSION_V1_APK), EXTERNAL_LOC_VERSION_PKG, false);
+            // now replace the app with an update marked for internalOnly and as forward locked
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(getTestAppFilePath(
+                    EXTERNAL_LOC_VERSION_V2_APK), EXTERNAL_LOC_VERSION_PKG, true);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(EXTERNAL_LOC_VERSION_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that updating a forward-locked app will install
+     * the update onto the device's forward-locked location
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndUpdateNoLocForwardLockedApp()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test updating a forward-locked app with no installLocation pref set");
+
+        try {
+            // install the app
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(getTestAppFilePath(
+                    NO_LOC_VERSION_V1_APK), NO_LOC_VERSION_PKG, false);
+            // now replace the app with an update marked for internalOnly...
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(getTestAppFilePath(
+                    NO_LOC_VERSION_V2_APK), NO_LOC_VERSION_PKG, true);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(NO_LOC_VERSION_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with all permissions set can be installed on SD card
+     * and then launched without crashing.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchAllPermsAppOnSD()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app with all perms set, installed on SD card");
+
+        try {
+            // install the app
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    ALL_PERMS_APK), ALL_PERMS_PKG, false);
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(ALL_PERMS_PKG);
+            assert(testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(ALL_PERMS_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with ACCESS_FINE_LOCATION (GPS) permissions can
+     * run without permissions errors.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchFLPermsAppOnSD()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app with location perms set, installed on SD card");
+
+        try {
+            // install the app and verify we can launch it without permissions errors
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_FL_APK), SHARED_PERMS_FL_PKG, false);
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_FL_PKG);
+            assert(testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(SHARED_PERMS_FL_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with BLUE_TOOTH permissions can
+     * run without permissions errors.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchBTPermsAppOnSD()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app with bluetooth perms set, installed on SD card");
+
+        try {
+            // install the app and verify we can launch it without permissions errors
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_BT_APK), SHARED_PERMS_BT_PKG, false);
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_BT_PKG);
+            assert(testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(SHARED_PERMS_BT_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that a shared app with no explicit permissions throws a
+     * SecurityException when launched if its other shared apps are not installed.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchSharedPermsAppOnSD_NoPerms()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app with no explicit perms set, installed on SD card");
+
+        try {
+            // Make sure the 2 shared apps with needed permissions are not installed...
+            mPMHostUtils.uninstallApp(SHARED_PERMS_FL_PKG);
+            mPMHostUtils.uninstallApp(SHARED_PERMS_BT_PKG);
+
+            // now install the app and see if when we launch it we get a permissions error
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_APK), SHARED_PERMS_PKG, false);
+
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_PKG);
+            assertEquals("Shared perms app should fail to run", false, testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(SHARED_PERMS_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that a shared app with no explicit permissions can run if its other
+     * shared apps are installed.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchSharedPermsAppOnSD_GrantedPerms()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app with no explicit perms set, installed on SD card");
+
+        try {
+            // install the 2 shared apps with needed permissions first
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_FL_APK), SHARED_PERMS_FL_PKG, false);
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_BT_APK), SHARED_PERMS_BT_PKG, false);
+
+            // now install the test app and see if we can launch it without errors
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_APK), SHARED_PERMS_PKG, false);
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_PKG);
+            assert(testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(SHARED_PERMS_PKG);
+            mPMHostUtils.uninstallApp(SHARED_PERMS_BT_PKG);
+            mPMHostUtils.uninstallApp(SHARED_PERMS_FL_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with ACCESS_FINE_LOCATION (GPS) permissions can
+     * run without permissions errors even after a reboot
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchFLPermsAppOnSD_Reboot()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app with location perms set, installed on SD card");
+
+        try {
+            // install the app and verify we can launch it without permissions errors
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_FL_APK), SHARED_PERMS_FL_PKG, false);
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_FL_PKG);
+            assert(testsPassed);
+
+            mPMHostUtils.rebootDevice();
+
+            testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_FL_PKG);
+            assert(testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(SHARED_PERMS_FL_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that a shared app with no explicit permissions can run if its other
+     * shared apps are installed, even after a reboot.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchSharedPermsAppOnSD_Reboot()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app on SD, with no explicit perms set after reboot");
+
+        try {
+            // install the 2 shared apps with needed permissions first
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_FL_APK), SHARED_PERMS_FL_PKG, false);
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_BT_APK), SHARED_PERMS_BT_PKG, false);
+
+            // now install the test app and see if we can launch it without errors
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_APK), SHARED_PERMS_PKG, false);
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_PKG);
+            assert(testsPassed);
+
+            // reboot
+            mPMHostUtils.rebootDevice();
+
+            // Verify we can still launch the app
+            testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_PKG);
+            assert(testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(SHARED_PERMS_PKG);
+            mPMHostUtils.uninstallApp(SHARED_PERMS_BT_PKG);
+            mPMHostUtils.uninstallApp(SHARED_PERMS_FL_PKG);
+        }
+    }
 }
diff --git a/core/tests/hosttests/src/android/content/pm/PackageManagerStressHostTests.java b/core/tests/hosttests/src/android/content/pm/PackageManagerStressHostTests.java
new file mode 100644
index 0000000..715c55b
--- /dev/null
+++ b/core/tests/hosttests/src/android/content/pm/PackageManagerStressHostTests.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.Log;
+import com.android.hosttest.DeviceTestCase;
+import com.android.hosttest.DeviceTestSuite;
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.Test;
+
+/**
+ * Set of tests that verify host side stress scenarios (large apps, multiple upgrades, etc.)
+ */
+public class PackageManagerStressHostTests extends DeviceTestCase {
+
+    private static final String LOG_TAG = "PackageManagerStressHostTests";
+    private PackageManagerHostTestUtils mPMHostUtils = null;
+
+    // Path to the app repository and various subdirectories of it
+    // Note: These stress tests require large apks that cannot be checked into the tree.
+    // These variables define static locations that point to existing APKs (not built from
+    // the tree) which can be used by the the stress tests in this file.
+    private static final String LARGE_APPS_DIRECTORY_NAME = "largeApps";
+    private static final String MISC_APPS_DIRECTORY_NAME = "miscApps";
+    private static final String VERSIONED_APPS_DIRECTORY_NAME = "versionedApps";
+    private static final String MANY_APPS_DIRECTORY_NAME = "manyApps";
+
+    // Note: An external environment variable "ANDROID_TEST_APP_REPOSITORY" must be set
+    // which points to the root location of the app respository.
+    private static String AppRepositoryPath = null;
+
+    // Large apps (>1mb) - filenames and their corresponding package names:
+    private static enum APK {
+            FILENAME,
+            PACKAGENAME;
+    }
+    private static final String[][] LARGE_APPS = {
+       {"External1mb.apk", "com.appsonsd.mytests.External1mb"},
+       {"External2mb.apk", "com.appsonsd.mytests.External2mb"},
+       {"External3mb.apk", "com.appsonsd.mytests.External3mb"},
+       {"External4mb.apk", "com.appsonsd.mytests.External4mb"},
+       {"External5mb.apk", "com.appsonsd.mytests.External5mb"},
+       {"External6mb.apk", "com.appsonsd.mytests.External6mb"},
+       {"External7mb.apk", "com.appsonsd.mytests.External7mb"},
+       {"External8mb.apk", "com.appsonsd.mytests.External8mb"},
+       {"External9mb.apk", "com.appsonsd.mytests.External9mb"},
+       {"External10mb.apk", "com.appsonsd.mytests.External10mb"},
+       {"External16mb.apk", "com.appsonsd.mytests.External16mb"},
+       {"External28mb.apk", "com.appsonsd.mytests.External28mb"},
+       {"External34mb.apk", "com.appsonsd.mytests.External34mb"},
+       {"External46mb.apk", "com.appsonsd.mytests.External46mb"},
+       {"External58mb.apk", "com.appsonsd.mytests.External58mb"},
+       {"External65mb.apk", "com.appsonsd.mytests.External65mb"},
+       {"External72mb.apk", "com.appsonsd.mytests.External72mb"},
+       {"External79mb.apk", "com.appsonsd.mytests.External79mb"},
+       {"External86mb.apk", "com.appsonsd.mytests.External86mb"},
+       {"External93mb.apk", "com.appsonsd.mytests.External93mb"}};
+
+    // Various test files and their corresponding package names
+    private static final String AUTO_LOC_APK = "Auto241kb.apk";
+    private static final String AUTO_LOC_PKG = "com.appsonsd.mytests.Auto241kb";
+    private static final String INTERNAL_LOC_APK = "Internal781kb.apk";
+    private static final String INTERNAL_LOC_PKG = "com.appsonsd.mytests.Internal781kb";
+    private static final String EXTERNAL_LOC_APK = "External931kb.apk";
+    private static final String EXTERNAL_LOC_PKG = "com.appsonsd.mytests.External931kb";
+    private static final String NO_LOC_APK = "Internal751kb_EclairSDK.apk";
+    private static final String NO_LOC_PKG = "com.appsonsd.mytests.Internal751kb_EclairSDK";
+    // Versioned test apps
+    private static final String VERSIONED_APPS_FILENAME_PREFIX = "External455kb_v";
+    private static final String VERSIONED_APPS_PKG = "com.appsonsd.mytests.External455kb";
+    private static final int VERSIONED_APPS_START_VERSION = 1;  // inclusive
+    private static final int VERSIONED_APPS_END_VERSION = 250;  // inclusive
+    // Large number of app installs
+    // @TODO: increase the max when we can install more apps
+    private static final int MANY_APPS_START = 1;
+    private static final int MANY_APPS_END = 100;
+    private static final String MANY_APPS_PKG_PREFIX = "com.appsonsd.mytests.External49kb_";
+    private static final String MANY_APPS_APK_PREFIX = "External49kb_";
+
+    public static Test suite() {
+        return new DeviceTestSuite(PackageManagerStressHostTests.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // setup the PackageManager host tests utilities class, and get various paths we'll need...
+        mPMHostUtils = new PackageManagerHostTestUtils(getDevice());
+        AppRepositoryPath = System.getenv("ANDROID_TEST_APP_REPOSITORY");
+        assertNotNull(AppRepositoryPath);
+
+        // Make sure path ends with a separator
+        if (!AppRepositoryPath.endsWith(File.separator)) {
+            AppRepositoryPath += File.separator;
+        }
+    }
+
+    /**
+     * Get the absolute file system location of repository test app with given filename
+     * @param fileName the file name of the test app apk
+     * @return {@link String} of absolute file path
+     */
+    private String getRepositoryTestAppFilePath(String fileDirectory, String fileName) {
+        return String.format("%s%s%s%s", AppRepositoryPath, fileDirectory,
+                File.separator, fileName);
+    }
+
+    /**
+     * Get the absolute file system location of test app with given filename
+     * @param fileName the file name of the test app apk
+     * @return {@link String} of absolute file path
+     */
+    public String getTestAppFilePath(String fileName) {
+        return String.format("%s%s%s", getTestAppPath(), File.separator, fileName);
+    }
+
+    /**
+     * Stress test to verify that we can update an app multiple times on the SD card.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void testUpdateAppManyTimesOnSD() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test updating an app on SD numerous times");
+
+        // cleanup test app just in case it already exists
+        mPMHostUtils.uninstallApp(VERSIONED_APPS_PKG);
+        // grep for package to make sure its not installed
+        assertFalse(mPMHostUtils.doesPackageExist(VERSIONED_APPS_PKG));
+
+        try {
+            for (int i = VERSIONED_APPS_START_VERSION; i <= VERSIONED_APPS_END_VERSION; ++i) {
+                String currentApkName = String.format("%s%d.apk",
+                        VERSIONED_APPS_FILENAME_PREFIX, i);
+
+                Log.i(LOG_TAG, "Installing app " + currentApkName);
+                mPMHostUtils.installFile(getRepositoryTestAppFilePath(VERSIONED_APPS_DIRECTORY_NAME,
+                        currentApkName), true);
+                mPMHostUtils.waitForPackageManager();
+                assertTrue(mPMHostUtils.doesAppExistOnSDCard(VERSIONED_APPS_PKG));
+                assertTrue(mPMHostUtils.doesPackageExist(VERSIONED_APPS_PKG));
+            }
+        }
+        finally {
+            // cleanup test app
+            mPMHostUtils.uninstallApp(VERSIONED_APPS_PKG);
+            // grep for package to make sure its not installed
+            assertFalse(mPMHostUtils.doesPackageExist(VERSIONED_APPS_PKG));
+        }
+    }
+
+    /**
+     * Stress test to verify that an app can be installed, uninstalled, and
+     * reinstalled on SD many times.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void testUninstallReinstallAppOnSDManyTimes() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test updating an app on the SD card stays on the SD card");
+
+        // cleanup test app just in case it was already exists
+        mPMHostUtils.uninstallApp(EXTERNAL_LOC_PKG);
+        // grep for package to make sure its not installed
+        assertFalse(mPMHostUtils.doesPackageExist(EXTERNAL_LOC_PKG));
+
+        for (int i = 0; i <= 500; ++i) {
+            Log.i(LOG_TAG, "Installing app");
+
+            try {
+                // install the app
+                mPMHostUtils.installFile(getRepositoryTestAppFilePath(MISC_APPS_DIRECTORY_NAME,
+                        EXTERNAL_LOC_APK), false);
+                mPMHostUtils.waitForPackageManager();
+                assertTrue(mPMHostUtils.doesAppExistOnSDCard(EXTERNAL_LOC_PKG));
+                assertTrue(mPMHostUtils.doesPackageExist(EXTERNAL_LOC_PKG));
+            }
+            finally {
+                // now uninstall the app
+                Log.i(LOG_TAG, "Uninstalling app");
+                mPMHostUtils.uninstallApp(EXTERNAL_LOC_PKG);
+                mPMHostUtils.waitForPackageManager();
+                assertFalse(mPMHostUtils.doesPackageExist(EXTERNAL_LOC_PKG));
+            }
+        }
+    }
+
+    /**
+     * Stress test to verify that we can install, 20 large apps (>1mb each)
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void testInstallManyLargeAppsOnSD() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installing 20 large apps onto the sd card");
+
+        try {
+            // Install all the large apps
+            for (int i=0; i < LARGE_APPS.length; ++i) {
+                String apkName = LARGE_APPS[i][APK.FILENAME.ordinal()];
+                String pkgName = LARGE_APPS[i][APK.PACKAGENAME.ordinal()];
+
+                // cleanup test app just in case it already exists
+                mPMHostUtils.uninstallApp(pkgName);
+                // grep for package to make sure its not installed
+                assertFalse(mPMHostUtils.doesPackageExist(pkgName));
+
+                Log.i(LOG_TAG, "Installing app " + apkName);
+                // install the app
+                mPMHostUtils.installFile(getRepositoryTestAppFilePath(LARGE_APPS_DIRECTORY_NAME,
+                        apkName), false);
+                mPMHostUtils.waitForPackageManager();
+                assertTrue(mPMHostUtils.doesAppExistOnSDCard(pkgName));
+                assertTrue(mPMHostUtils.doesPackageExist(pkgName));
+            }
+        }
+        finally {
+            // Cleanup - ensure we uninstall all large apps if they were installed
+            for (int i=0; i < LARGE_APPS.length; ++i) {
+                String apkName = LARGE_APPS[i][APK.FILENAME.ordinal()];
+                String pkgName = LARGE_APPS[i][APK.PACKAGENAME.ordinal()];
+
+                Log.i(LOG_TAG, "Uninstalling app " + apkName);
+                // cleanup test app just in case it was accidently installed
+                mPMHostUtils.uninstallApp(pkgName);
+                // grep for package to make sure its not installed anymore
+                assertFalse(mPMHostUtils.doesPackageExist(pkgName));
+                assertFalse(mPMHostUtils.doesAppExistOnSDCard(pkgName));
+            }
+        }
+    }
+
+    /**
+     * Stress test to verify that we can install many small apps onto SD.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void testInstallManyAppsOnSD() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installing 500 small apps onto SD");
+
+        try {
+            for (int i = MANY_APPS_START; i <= MANY_APPS_END; ++i) {
+                String currentPkgName = String.format("%s%d", MANY_APPS_PKG_PREFIX, i);
+
+                // cleanup test app just in case it already exists
+                mPMHostUtils.uninstallApp(currentPkgName);
+                // grep for package to make sure its not installed
+                assertFalse(mPMHostUtils.doesPackageExist(currentPkgName));
+
+                String currentApkName = String.format("%s%d.apk", MANY_APPS_APK_PREFIX, i);
+                Log.i(LOG_TAG, "Installing app " + currentApkName);
+                mPMHostUtils.installFile(getRepositoryTestAppFilePath(MANY_APPS_DIRECTORY_NAME,
+                        currentApkName), true);
+                mPMHostUtils.waitForPackageManager();
+                assertTrue(mPMHostUtils.doesAppExistOnSDCard(currentPkgName));
+                assertTrue(mPMHostUtils.doesPackageExist(currentPkgName));
+            }
+        }
+        finally {
+            for (int i = MANY_APPS_START; i <= MANY_APPS_END; ++i) {
+                String currentPkgName = String.format("%s%d", MANY_APPS_PKG_PREFIX, i);
+
+                // cleanup test app
+                mPMHostUtils.uninstallApp(currentPkgName);
+                // grep for package to make sure its not installed
+                assertFalse(mPMHostUtils.doesPackageExist(currentPkgName));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.mk
new file mode 100644
index 0000000..a887bac
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := AutoLocVersionedTestApp_v1
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/AndroidManifest.xml b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/AndroidManifest.xml
new file mode 100644
index 0000000..867871d
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.autolocversionedtestapp"
+       android:installLocation="auto"
+       android:versionCode="1"
+       android:versionName="1.0">
+
+    <application android:label="AutoLocVersionedTestApp_v1"/>
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/src/com/android/framework/autolocversionedtestapp/AutoLocVersionedTestAppActivity.java b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/src/com/android/framework/autolocversionedtestapp/AutoLocVersionedTestAppActivity.java
new file mode 100644
index 0000000..49575b7
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/src/com/android/framework/autolocversionedtestapp/AutoLocVersionedTestAppActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.autolocversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class AutoLocVersionedTestAppActivity extends Activity {
+
+}
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.mk
new file mode 100644
index 0000000..69084bf
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := AutoLocVersionedTestApp_v2
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/AndroidManifest.xml b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/AndroidManifest.xml
new file mode 100644
index 0000000..98e5606
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.autolocversionedtestapp"
+       android:installLocation="auto"
+       android:versionCode="2"
+       android:versionName="2.0">
+
+    <application android:label="AutoLocVersionedTestApp_v2"/>
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/src/com/android/framework/autolocversionedtestapp/AutoLocVersionedTestAppActivity.java b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/src/com/android/framework/autolocversionedtestapp/AutoLocVersionedTestAppActivity.java
new file mode 100644
index 0000000..49575b7
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/src/com/android/framework/autolocversionedtestapp/AutoLocVersionedTestAppActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.autolocversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class AutoLocVersionedTestAppActivity extends Activity {
+
+}
diff --git a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk
new file mode 100644
index 0000000..c70c1d3
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalLocAllPermsTestApp
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..0c502c0
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/AndroidManifest.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externallocallpermstestapp"
+       android:installLocation="preferExternal">
+
+    <uses-permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
+    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
+    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
+    <uses-permission android:name="android.permission.BATTERY_STATS" />
+    <uses-permission android:name="android.permission.BIND_APPWIDGET" />
+    <uses-permission android:name="android.permission.BIND_INPUT_METHOD" />
+    <uses-permission android:name="android.permission.BLUETOOTH" />
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <uses-permission android:name="android.permission.BRICK" />
+    <uses-permission android:name="android.permission.BROADCAST_PACKAGE_REMOVED" />
+    <uses-permission android:name="android.permission.BROADCAST_SMS" />
+    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+    <uses-permission android:name="android.permission.BROADCAST_WAP_PUSH" />
+    <uses-permission android:name="android.permission.CALL_PHONE" />
+    <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
+    <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
+    <uses-permission android:name="android.permission.CONTROL_LOCATION_UPDATES" />
+    <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
+    <uses-permission android:name="android.permission.DELETE_PACKAGES" />
+    <uses-permission android:name="android.permission.DEVICE_POWER" />
+    <uses-permission android:name="android.permission.DIAGNOSTIC" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.DUMP" />
+    <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+    <uses-permission android:name="android.permission.FACTORY_TEST" />
+    <uses-permission android:name="android.permission.FLASHLIGHT" />
+    <uses-permission android:name="android.permission.FORCE_BACK" />
+    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
+    <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.GLOBAL_SEARCH" />
+    <uses-permission android:name="android.permission.HARDWARE_TEST" />
+    <uses-permission android:name="android.permission.INJECT_EVENTS" />
+    <uses-permission android:name="android.permission.INSTALL_LOCATION_PROVIDER" />
+    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
+    <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
+    <uses-permission android:name="android.permission.MASTER_CLEAR" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
+    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
+    <uses-permission android:name="android.permission.PERSISTENT_ACTIVITY" />
+    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
+    <uses-permission android:name="android.permission.READ_CALENDAR" />
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
+    <uses-permission android:name="android.permission.READ_HISTORY_BOOKMARKS" />
+    <uses-permission android:name="android.permission.READ_INPUT_STATE" />
+    <uses-permission android:name="android.permission.READ_LOGS" />
+    <uses-permission android:name="android.permission.READ_OWNER_DATA" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.READ_SMS" />
+    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
+    <uses-permission android:name="android.permission.READ_SYNC_STATS" />
+    <uses-permission android:name="android.permission.REBOOT" />
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+    <uses-permission android:name="android.permission.RECEIVE_MMS" />
+    <uses-permission android:name="android.permission.RECEIVE_SMS" />
+    <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.REORDER_TASKS" />
+    <uses-permission android:name="android.permission.RESTART_PACKAGES" />
+    <uses-permission android:name="android.permission.SEND_SMS" />
+    <uses-permission android:name="android.permission.SET_ACTIVITY_WATCHER" />
+    <uses-permission android:name="android.permission.SET_ALWAYS_FINISH" />
+    <uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
+    <uses-permission android:name="android.permission.SET_DEBUG_APP" />
+    <uses-permission android:name="android.permission.SET_ORIENTATION" />
+    <uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
+    <uses-permission android:name="android.permission.SET_PROCESS_LIMIT" />
+    <uses-permission android:name="android.permission.SET_TIME_ZONE" />
+    <uses-permission android:name="android.permission.SET_WALLPAPER" />
+    <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
+    <uses-permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES" />
+    <uses-permission android:name="android.permission.STATUS_BAR" />
+    <uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_READ" />
+    <uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE" />
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
+    <uses-permission android:name="android.permission.VIBRATE" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
+    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_GSERVICES" />
+    <uses-permission android:name="android.permission.WRITE_HISTORY_BOOKMARKS" />
+    <uses-permission android:name="android.permission.WRITE_OWNER_DATA" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SMS" />
+    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.externallocallpermstestapp"
+                     android:label="Test for instrumentation with an app granted all permissions" />
+</manifest>
diff --git a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/src/com/android/framework/externallocallpermstestapp/ExternalLocAllPermsTest.java b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/src/com/android/framework/externallocallpermstestapp/ExternalLocAllPermsTest.java
new file mode 100644
index 0000000..8456255
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/src/com/android/framework/externallocallpermstestapp/ExternalLocAllPermsTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externallocallpermstestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import junit.framework.TestCase;
+
+
+public class ExternalLocAllPermsTest extends TestCase {
+    /**
+     * Test method that should get run. Doesn't need to actually do anything here,
+     * we just need to verify the test runs without errors.
+     */
+    public void testInstrumentationCanRun() {
+    }
+}
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.mk
new file mode 100644
index 0000000..05f62cd
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalLocVersionedTestApp_v1
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/AndroidManifest.xml
new file mode 100644
index 0000000..84bd5df
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externallocversionedtestapp"
+       android:installLocation="preferExternal"
+       android:versionCode="1"
+       android:versionName="1.0">
+
+    <application android:label="ExternalLocVersionedTestApp_v1"/>
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/src/com/android/framework/externallocversionedtestapp/ExternalLocVersionedTestAppActivity.java b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/src/com/android/framework/externallocversionedtestapp/ExternalLocVersionedTestAppActivity.java
new file mode 100644
index 0000000..a7487c2
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/src/com/android/framework/externallocversionedtestapp/ExternalLocVersionedTestAppActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externallocversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class ExternalLocVersionedTestAppActivity extends Activity {
+
+}
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.mk
new file mode 100644
index 0000000..aa31759
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalLocVersionedTestApp_v2
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/AndroidManifest.xml
new file mode 100644
index 0000000..7acba152
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externallocversionedtestapp"
+       android:installLocation="preferExternal"
+       android:versionCode="2"
+       android:versionName="2.0">
+
+    <application android:label="ExternalLocVersionedTestApp_v2"/>
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/src/com/android/framework/externallocversionedtestapp/ExternalLocVersionedTestAppActivity.java b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/src/com/android/framework/externallocversionedtestapp/ExternalLocVersionedTestAppActivity.java
new file mode 100644
index 0000000..a7487c2
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/src/com/android/framework/externallocversionedtestapp/ExternalLocVersionedTestAppActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externallocversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class ExternalLocVersionedTestAppActivity extends Activity {
+
+}
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk
new file mode 100644
index 0000000..7946e1a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalSharedPermsTestApp
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPerms/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalSharedPerms/AndroidManifest.xml
new file mode 100644
index 0000000..263a0fb
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPerms/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externalsharedpermstestapp"
+       android:installLocation="preferExternal"
+       android:versionCode="1"
+       android:versionName="1.0"
+       android:sharedUserId="com.android.framework.externalsharedpermstestapp">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.externalsharedpermstestapp"
+                     android:label="Test for instrumentation with an external app with shared permissions (BT and FL)" />
+</manifest>
+
+
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPerms/src/com/android/framework/externalsharedpermstestapp/ExternalSharedPermsTest.java b/core/tests/hosttests/test-apps/ExternalSharedPerms/src/com/android/framework/externalsharedpermstestapp/ExternalSharedPermsTest.java
new file mode 100644
index 0000000..da9600c
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPerms/src/com/android/framework/externalsharedpermstestapp/ExternalSharedPermsTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externalsharedpermstestapp;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+
+import android.util.Log;
+
+import android.test.InstrumentationTestCase;
+
+public class ExternalSharedPermsTest extends InstrumentationTestCase
+{
+    private static final int REQUEST_ENABLE_BT = 2;
+
+    /** The use of location manager and bluetooth below are simply to simulate an app that
+     *  tries to use them, so we can verify whether permissions are granted and accessible.
+     * */
+    public void testRunLocationAndBluetooth()
+    {
+        LocationManager locationManager = (LocationManager)getInstrumentation().getContext(
+                ).getSystemService(Context.LOCATION_SERVICE);
+        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
+                new LocationListener() {
+                        public void onLocationChanged(Location location) {}
+                        public void onProviderDisabled(String provider) {}
+                        public void onProviderEnabled(String provider) {}
+                        public void onStatusChanged(String provider, int status, Bundle extras) {}
+                }
+        );
+        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        if ((mBluetoothAdapter != null) && (!mBluetoothAdapter.isEnabled())) {
+            mBluetoothAdapter.getName();
+        }
+    }
+}
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk
new file mode 100644
index 0000000..657d0a40
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalSharedPermsBTTestApp
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/AndroidManifest.xml
new file mode 100644
index 0000000..98f7177
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externalsharedpermsbttestapp"
+       android:installLocation="preferExternal"
+       android:versionCode="1"
+       android:versionName="1.0"
+       android:sharedUserId="com.android.framework.externalsharedpermstestapp">
+
+    <uses-permission android:name="android.permission.BLUETOOTH" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.externalsharedpermsbttestapp"
+                     android:label="Test for instrumentation with an external app granted BLUETOOTH permissions" />
+
+</manifest>
+
+
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/src/com/android/framework/externalsharedpermsbttestapp/ExternalSharedPermsBTTest.java b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/src/com/android/framework/externalsharedpermsbttestapp/ExternalSharedPermsBTTest.java
new file mode 100644
index 0000000..c7bcdfc
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/src/com/android/framework/externalsharedpermsbttestapp/ExternalSharedPermsBTTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externalsharedpermsbttestapp;
+
+import android.bluetooth.BluetoothAdapter;
+
+import android.test.InstrumentationTestCase;
+
+public class ExternalSharedPermsBTTest extends InstrumentationTestCase
+{
+    private static final int REQUEST_ENABLE_BT = 2;
+
+    /** The use of bluetooth below is simply to simulate an activity that tries to use bluetooth
+     *  upon creation, so we can verify whether permissions are granted and accessible to the
+     *  activity once it launches.
+     * */
+    public void testRunBluetooth()
+    {
+        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        if ((mBluetoothAdapter != null) && (!mBluetoothAdapter.isEnabled())) {
+            mBluetoothAdapter.getName();
+        }
+    }
+}
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk
new file mode 100644
index 0000000..d4450dc
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk
@@ -0,0 +1,29 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalSharedPermsDiffKeyTestApp
+
+LOCAL_CERTIFICATE := media
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/AndroidManifest.xml
new file mode 100644
index 0000000..d0e8fb9
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externalsharedpermsdiffkeytestapp"
+       android:installLocation="preferExternal"
+       android:versionCode="1"
+       android:versionName="1.0"
+       android:sharedUserId="com.android.framework.externalsharedpermstestapp">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.externalsharedpermsdiffkeytestapp"
+                     android:label="Test for instrumentation with an app with shared permissions but signed by different key" />
+</manifest>
+
+
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/src/com/android/framework/externalsharedpermsdiffkeytestapp/ExternalSharedPermsDiffKeyTest.java b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/src/com/android/framework/externalsharedpermsdiffkeytestapp/ExternalSharedPermsDiffKeyTest.java
new file mode 100644
index 0000000..adc906a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/src/com/android/framework/externalsharedpermsdiffkeytestapp/ExternalSharedPermsDiffKeyTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externalsharedpermsdiffkeytestapp;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.os.Bundle;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+
+import android.test.InstrumentationTestCase;
+
+public class ExternalSharedPermsDiffKeyTest extends InstrumentationTestCase
+{
+    private static final int REQUEST_ENABLE_BT = 2;
+
+    /** The use of location manager and bluetooth below are simply to simulate an app that
+     *  tries to use them, so we can verify whether permissions are granted and accessible.
+     * */
+    public void testRunBluetoothAndFineLocation()
+    {
+        LocationManager locationManager = (LocationManager)getInstrumentation().getContext(
+                ).getSystemService(Context.LOCATION_SERVICE);
+        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
+                new LocationListener() {
+                        public void onLocationChanged(Location location) {}
+                        public void onProviderDisabled(String provider) {}
+                        public void onProviderEnabled(String provider) {}
+                        public void onStatusChanged(String provider, int status, Bundle extras) {}
+                }
+        );
+        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        if ((mBluetoothAdapter != null) && (!mBluetoothAdapter.isEnabled())) {
+            mBluetoothAdapter.getName();
+        }
+        fail("this app was signed by a different cert and should crash/fail to run by now");
+    }
+}
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk
new file mode 100644
index 0000000..8154862
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalSharedPermsFLTestApp
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/AndroidManifest.xml
new file mode 100644
index 0000000..15cc912
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externalsharedpermsfltestapp"
+       android:installLocation="preferExternal"
+       android:versionCode="1"
+       android:versionName="1.0"
+       android:sharedUserId="com.android.framework.externalsharedpermstestapp">
+
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.externalsharedpermsfltestapp"
+                     android:label="Test for instrumentation with an app granted FINE_LOCATION permissions" />
+</manifest>
+
+
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/src/com/android/framework/externalsharedpermsfltestapp/ExternalSharedPermsFLTest.java b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/src/com/android/framework/externalsharedpermsfltestapp/ExternalSharedPermsFLTest.java
new file mode 100644
index 0000000..307034e
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/src/com/android/framework/externalsharedpermsfltestapp/ExternalSharedPermsFLTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externalsharedpermsfltestapp;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+
+import android.test.InstrumentationTestCase;
+
+public class ExternalSharedPermsFLTest extends InstrumentationTestCase
+{
+    /** The use of location manager below is simply to simulate an app that
+     *  tries to use it, so we can verify whether permissions are granted and accessible.
+     * */
+    public void testRunFineLocation()
+    {
+        LocationManager locationManager = (LocationManager)getInstrumentation().getContext(
+                ).getSystemService(Context.LOCATION_SERVICE);
+        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
+                new LocationListener() {
+                        public void onLocationChanged(Location location) {}
+                        public void onProviderDisabled(String provider) {}
+                        public void onProviderEnabled(String provider) {}
+                        public void onStatusChanged(String provider, int status, Bundle extras) {}
+                }
+        );
+    }
+}
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.mk
new file mode 100644
index 0000000..36413ee
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := NoLocVersionedTestApp_v1
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/AndroidManifest.xml b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/AndroidManifest.xml
new file mode 100644
index 0000000..c98f1c2
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.nolocversionedtestapp"
+       android:versionCode="1"
+       android:versionName="1.0">
+
+    <application android:label="NoLocVersionedTestApp_v1"/>
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/src/com/android/framework/nolocversionedtestapp/NoLocVersionedTestAppActivity.java b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/src/com/android/framework/nolocversionedtestapp/NoLocVersionedTestAppActivity.java
new file mode 100644
index 0000000..0540e5a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/src/com/android/framework/nolocversionedtestapp/NoLocVersionedTestAppActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.nolocversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class NoLocVersionedTestAppActivity extends Activity {
+
+}
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.mk
new file mode 100644
index 0000000..27d03b0
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := NoLocVersionedTestApp_v2
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/AndroidManifest.xml b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/AndroidManifest.xml
new file mode 100644
index 0000000..1af1e68
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.nolocversionedtestapp"
+       android:versionCode="2"
+       android:versionName="2.0">
+
+    <application android:label="NoLocVersionedTestApp_v2"/>
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/src/com/android/framework/nolocversionedtestapp/NoLocVersionedTestAppActivity.java b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/src/com/android/framework/nolocversionedtestapp/NoLocVersionedTestAppActivity.java
new file mode 100644
index 0000000..0540e5a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/src/com/android/framework/nolocversionedtestapp/NoLocVersionedTestAppActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.nolocversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class NoLocVersionedTestAppActivity extends Activity {
+
+}