diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index e8ae7e6bbd4ac..4688847b0354c 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -31,7 +31,14 @@ public class Environment { 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 class Environment { */ 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 @@ public class Environment { 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); diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index 60ea95c459f7f..57e208a349964 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -565,6 +565,25 @@ public interface IMountService extends IInterface { } return _result; } + + /** + * Returns whether the external storage is emulated. + */ + public boolean isExternalStorageEmulated() throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + boolean _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + mRemote.transact(Stub.TRANSACTION_isExternalStorageEmulated, _data, _reply, 0); + _reply.readException(); + _result = 0 != _reply.readInt(); + } finally { + _reply.recycle(); + _data.recycle(); + } + return _result; + } } private static final String DESCRIPTOR = "IMountService"; @@ -619,6 +638,8 @@ public interface IMountService extends IInterface { static final int TRANSACTION_getMountedObbPath = IBinder.FIRST_CALL_TRANSACTION + 24; + static final int TRANSACTION_isExternalStorageEmulated = IBinder.FIRST_CALL_TRANSACTION + 25; + /** * Cast an IBinder object into an IMountService interface, generating a * proxy if needed. @@ -889,6 +910,13 @@ public interface IMountService extends IInterface { reply.writeString(mountedPath); return true; } + case TRANSACTION_isExternalStorageEmulated: { + data.enforceInterface(DESCRIPTOR); + boolean emulated = isExternalStorageEmulated(); + reply.writeNoException(); + reply.writeInt(emulated ? 1 : 0); + return true; + } } return super.onTransact(code, data, reply, flags); } @@ -1043,4 +1071,9 @@ public interface IMountService extends IInterface { * Unregisters an IMountServiceListener */ public void unregisterListener(IMountServiceListener listener) throws RemoteException; + + /** + * Returns whether or not the external storage is emulated. + */ + public boolean isExternalStorageEmulated() throws RemoteException; } diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp index 3ad9319a8f359..17a961be8d077 100644 --- a/libs/storage/IMountService.cpp +++ b/libs/storage/IMountService.cpp @@ -47,6 +47,7 @@ enum { TRANSACTION_unmountObb, TRANSACTION_isObbMounted, TRANSACTION_getMountedObbPath, + TRANSACTION_isExternalStorageEmulated, }; class BpMountService: public BpInterface diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index ce10f5b71d458..e6624ae11c11b 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -440,7 +440,7 @@ public class DefaultContainerService extends IntentService { String status = Environment.getExternalStorageState(); long availSDSize = -1; boolean mediaAvailable = false; - if (status.equals(Environment.MEDIA_MOUNTED)) { + if (!Environment.isExternalStorageEmulated() && status.equals(Environment.MEDIA_MOUNTED)) { StatFs sdStats = new StatFs( Environment.getExternalStorageDirectory().getPath()); availSDSize = (long)sdStats.getAvailableBlocks() * diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 295047c8b7525..baa5016fc032d 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -1240,6 +1240,10 @@ class MountService extends IMountService.Stub return mLegacyState; } + public boolean isExternalStorageEmulated() { + return mEmulateExternalStorage; + } + public int mountVolume(String path) { validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);