Add API to check for emulated external storage

When the storage is emulated, we don't want to install ASEC containers
to it. This adds the API to check when the external storage is emulated
and uses it to check whether or not to install packages to the external
storage in an ASEC container.

Bug: 3024387
Change-Id: Ia0318aca9e4938a4897deaada5603a4c7c1d0f48
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index e8ae7e6..4688847 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -31,7 +31,14 @@
 
     private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
 
-    private static IMountService mMntSvc = null;
+    private static class MountServiceHolder {
+        static IMountService mSingleton = IMountService.Stub.asInterface(ServiceManager
+                .getService("mount"));
+    }
+
+    private static final Object mLock = new Object();
+
+    private volatile static Boolean mIsExternalStorageEmulated = null;
 
     /**
      * Gets the Android root directory.
@@ -382,11 +389,8 @@
      */
     public static String getExternalStorageState() {
         try {
-            if (mMntSvc == null) {
-                mMntSvc = IMountService.Stub.asInterface(ServiceManager
-                                                         .getService("mount"));
-            }
-            return mMntSvc.getVolumeState(getExternalStorageDirectory().toString());
+            return MountServiceHolder.mSingleton.getVolumeState(getExternalStorageDirectory()
+                    .toString());
         } catch (Exception rex) {
             return Environment.MEDIA_REMOVED;
         }
@@ -405,6 +409,32 @@
                 com.android.internal.R.bool.config_externalStorageRemovable);
     }
 
+    /**
+     * Returns whether the device has an external storage device which is
+     * emulated. If true, the device does not have real external storage
+     * and certain system services such as the package manager use this
+     * to determine where to install an application.
+     *
+     * @hide
+     */
+    public static boolean isExternalStorageEmulated() {
+        if (mIsExternalStorageEmulated == null) {
+            synchronized (mLock) {
+                if (mIsExternalStorageEmulated == null) {
+                    boolean externalStorageEmulated;
+                    try {
+                        externalStorageEmulated =
+                                MountServiceHolder.mSingleton.isExternalStorageEmulated();
+                    } catch (Exception e) {
+                        externalStorageEmulated = false;
+                    }
+                    mIsExternalStorageEmulated = Boolean.valueOf(externalStorageEmulated);
+                }
+            }
+        }
+        return mIsExternalStorageEmulated;
+    }
+
     static File getDirectory(String variableName, String defaultPath) {
         String path = System.getenv(variableName);
         return path == null ? new File(defaultPath) : new File(path);