diff options
Diffstat (limited to 'core')
| -rw-r--r-- | core/java/android/app/ContextImpl.java | 22 | ||||
| -rw-r--r-- | core/java/android/os/Environment.java | 64 | ||||
| -rw-r--r-- | core/java/android/os/storage/IMountService.java | 40 |
3 files changed, 98 insertions, 28 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 8e9f3bb..0ba2ac5 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -92,6 +92,7 @@ import android.os.ServiceManager; import android.os.UserHandle; import android.os.SystemVibrator; import android.os.UserManager; +import android.os.storage.IMountService; import android.os.storage.StorageManager; import android.print.IPrintManager; import android.print.PrintManager; @@ -864,7 +865,9 @@ class ContextImpl extends Context { if (mExternalObbDirs == null) { mExternalObbDirs = Environment.buildExternalStorageAppObbDirs(getPackageName()); } - return mExternalObbDirs; + + // Create dirs if needed + return ensureDirsExistOrFilter(mExternalObbDirs); } } @@ -2127,14 +2130,25 @@ class ContextImpl extends Context { * Ensure that given directories exist, trying to create them if missing. If * unable to create, they are filtered by replacing with {@code null}. */ - private static File[] ensureDirsExistOrFilter(File[] dirs) { + private File[] ensureDirsExistOrFilter(File[] dirs) { File[] result = new File[dirs.length]; for (int i = 0; i < dirs.length; i++) { File dir = dirs[i]; if (!dir.exists()) { if (!dir.mkdirs()) { - Log.w(TAG, "Failed to ensure directory: " + dir); - dir = null; + // Failing to mkdir() may be okay, since we might not have + // enough permissions; ask vold to create on our behalf. + final IMountService mount = IMountService.Stub.asInterface( + ServiceManager.getService("mount")); + int res = -1; + try { + res = mount.mkdirs(getPackageName(), dir.getAbsolutePath()); + } catch (RemoteException e) { + } + if (res != 0) { + Log.w(TAG, "Failed to ensure directory: " + dir); + dir = null; + } } } result[i] = dir; diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 5b36bca..fc53580 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -109,29 +109,36 @@ public class Environment { // TODO: generalize further to create package-specific environment // TODO: add support for secondary external storage - private final File[] mExternalDirs; - private final File mMediaDir; + /** External storage dirs, as visible to vold */ + private final File[] mExternalDirsForVold; + /** External storage dirs, as visible to apps */ + private final File[] mExternalDirsForApp; + /** Primary emulated storage dir for direct access */ + private final File mEmulatedDirForDirect; public UserEnvironment(int userId) { // See storage config details at http://source.android.com/tech/storage/ String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE); - String rawEmulatedStorageTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET); + String rawEmulatedSource = System.getenv(ENV_EMULATED_STORAGE_SOURCE); + String rawEmulatedTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET); String rawMediaStorage = System.getenv(ENV_MEDIA_STORAGE); if (TextUtils.isEmpty(rawMediaStorage)) { rawMediaStorage = "/data/media"; } - if (!TextUtils.isEmpty(rawEmulatedStorageTarget)) { + if (!TextUtils.isEmpty(rawEmulatedTarget)) { // Device has emulated storage; external storage paths should have // userId burned into them. final String rawUserId = Integer.toString(userId); - final File emulatedBase = new File(rawEmulatedStorageTarget); + final File emulatedSourceBase = new File(rawEmulatedSource); + final File emulatedTargetBase = new File(rawEmulatedTarget); final File mediaBase = new File(rawMediaStorage); // /storage/emulated/0 - mExternalDirs = new File[] { buildPath(emulatedBase, rawUserId) }; + mExternalDirsForVold = new File[] { buildPath(emulatedSourceBase, rawUserId) }; + mExternalDirsForApp = new File[] { buildPath(emulatedTargetBase, rawUserId) }; // /data/media/0 - mMediaDir = buildPath(mediaBase, rawUserId); + mEmulatedDirForDirect = buildPath(mediaBase, rawUserId); } else { // Device has physical external storage; use plain paths. @@ -141,15 +148,16 @@ public class Environment { } // /storage/sdcard0 - mExternalDirs = new File[] { new File(rawExternalStorage) }; + mExternalDirsForVold = new File[] { new File(rawExternalStorage) }; + mExternalDirsForApp = new File[] { new File(rawExternalStorage) }; // /data/media - mMediaDir = new File(rawMediaStorage); + mEmulatedDirForDirect = new File(rawMediaStorage); } } @Deprecated public File getExternalStorageDirectory() { - return mExternalDirs[0]; + return mExternalDirsForApp[0]; } @Deprecated @@ -157,44 +165,56 @@ public class Environment { return buildExternalStoragePublicDirs(type)[0]; } - public File[] getExternalDirs() { - return mExternalDirs; + public File[] getExternalDirsForVold() { + return mExternalDirsForVold; + } + + public File[] getExternalDirsForApp() { + return mExternalDirsForApp; } public File getMediaDir() { - return mMediaDir; + return mEmulatedDirForDirect; } public File[] buildExternalStoragePublicDirs(String type) { - return buildPaths(mExternalDirs, type); + return buildPaths(mExternalDirsForApp, type); } public File[] buildExternalStorageAndroidDataDirs() { - return buildPaths(mExternalDirs, DIR_ANDROID, DIR_DATA); + return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA); } public File[] buildExternalStorageAndroidObbDirs() { - return buildPaths(mExternalDirs, DIR_ANDROID, DIR_OBB); + return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_OBB); } public File[] buildExternalStorageAppDataDirs(String packageName) { - return buildPaths(mExternalDirs, DIR_ANDROID, DIR_DATA, packageName); + return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName); + } + + public File[] buildExternalStorageAppDataDirsForVold(String packageName) { + return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_DATA, packageName); } public File[] buildExternalStorageAppMediaDirs(String packageName) { - return buildPaths(mExternalDirs, DIR_ANDROID, DIR_MEDIA, packageName); + return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_MEDIA, packageName); } public File[] buildExternalStorageAppObbDirs(String packageName) { - return buildPaths(mExternalDirs, DIR_ANDROID, DIR_OBB, packageName); + return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_OBB, packageName); + } + + public File[] buildExternalStorageAppObbDirsForVold(String packageName) { + return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_OBB, packageName); } public File[] buildExternalStorageAppFilesDirs(String packageName) { - return buildPaths(mExternalDirs, DIR_ANDROID, DIR_DATA, packageName, DIR_FILES); + return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName, DIR_FILES); } public File[] buildExternalStorageAppCacheDirs(String packageName) { - return buildPaths(mExternalDirs, DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE); + return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE); } } @@ -344,7 +364,7 @@ public class Environment { */ public static File getExternalStorageDirectory() { throwIfUserRequired(); - return sCurrentUser.getExternalDirs()[0]; + return sCurrentUser.getExternalDirsForApp()[0]; } /** {@hide} */ diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index fc18617..51ba2f6 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -20,9 +20,7 @@ import android.os.Binder; import android.os.IBinder; import android.os.IInterface; import android.os.Parcel; -import android.os.Parcelable; import android.os.RemoteException; -import android.os.storage.StorageVolume; /** * WARNING! Update IMountService.h and IMountService.cpp if you change this @@ -737,7 +735,25 @@ public interface IMountService extends IInterface { _data.recycle(); } return _result; + } + @Override + public int mkdirs(String callingPkg, String path) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + int _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(callingPkg); + _data.writeString(path); + mRemote.transact(Stub.TRANSACTION_mkdirs, _data, _reply, 0); + _reply.readException(); + _result = _reply.readInt(); + } finally { + _reply.recycle(); + _data.recycle(); + } + return _result; } } @@ -811,6 +827,8 @@ public interface IMountService extends IInterface { static final int TRANSACTION_fixPermissionsSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 33; + static final int TRANSACTION_mkdirs = IBinder.FIRST_CALL_TRANSACTION + 34; + /** * Cast an IBinder object into an IMountService interface, generating a * proxy if needed. @@ -1154,6 +1172,15 @@ public interface IMountService extends IInterface { reply.writeInt(resultCode); return true; } + case TRANSACTION_mkdirs: { + data.enforceInterface(DESCRIPTOR); + String callingPkg = data.readString(); + String path = data.readString(); + int result = mkdirs(callingPkg, path); + reply.writeNoException(); + reply.writeInt(result); + return true; + } } return super.onTransact(code, data, reply, flags); } @@ -1376,4 +1403,13 @@ public interface IMountService extends IInterface { */ public int fixPermissionsSecureContainer(String id, int gid, String filename) throws RemoteException; + + /** + * Ensure that all directories along given path exist, creating parent + * directories as needed. Validates that given path is absolute and that it + * contains no relative "." or ".." paths or symlinks. Also ensures that + * path belongs to a volume managed by vold, and that path is either + * external storage data or OBB directory belonging to calling app. + */ + public int mkdirs(String callingPkg, String path) throws RemoteException; } |
