Skip to content

Commit 4fbbda4

Browse files
committed
Handle multi-user mountObb() requests.
Since emulated external storage paths differ based on execution context, carefully fix up paths for various use-cases: 1. When sending paths to DefaultContainerService, always scope OBB paths as belonging to USER_OWNER. 2. When sending paths to vold, always build emulated storage paths visible to root. 3. Always use the original untouched path when talking with apps. Mount OBB containers using shared app GID, so that an app can read the mount point across users. Handle legacy paths like "/sdcard" by resolving the canonical path before sending to MountService. Move tests to servicestests, and add tests for new path generation logic. Bug: 7212801 Change-Id: I078c52879cd08d9c8a52cc8c83ac7ced1e8035e7
1 parent 5e21bf9 commit 4fbbda4

File tree

11 files changed

+273
-162
lines changed

11 files changed

+273
-162
lines changed

core/java/android/os/Environment.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class Environment {
3131
private static final String TAG = "Environment";
3232

3333
private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
34+
private static final String ENV_EMULATED_STORAGE_SOURCE = "EMULATED_STORAGE_SOURCE";
3435
private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET";
3536
private static final String ENV_MEDIA_STORAGE = "MEDIA_STORAGE";
3637

@@ -134,6 +135,10 @@ public File getExternalStorageDirectory() {
134135
return mExternalStorage;
135136
}
136137

138+
public File getExternalStorageObbDirectory() {
139+
return mExternalStorageAndroidObb;
140+
}
141+
137142
public File getExternalStoragePublicDirectory(String type) {
138143
return new File(mExternalStorage, type);
139144
}
@@ -302,6 +307,23 @@ public static File getLegacyExternalStorageDirectory() {
302307
return new File(System.getenv(ENV_EXTERNAL_STORAGE));
303308
}
304309

310+
/** {@hide} */
311+
public static File getLegacyExternalStorageObbDirectory() {
312+
return buildPath(getLegacyExternalStorageDirectory(), DIRECTORY_ANDROID, "obb");
313+
}
314+
315+
/** {@hide} */
316+
public static File getEmulatedStorageSource(int userId) {
317+
// /mnt/shell/emulated/0
318+
return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), String.valueOf(userId));
319+
}
320+
321+
/** {@hide} */
322+
public static File getEmulatedStorageObbSource() {
323+
// /mnt/shell/emulated/obb
324+
return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), "obb");
325+
}
326+
305327
/**
306328
* Standard directory in which to place any audio files that should be
307329
* in the regular list of music for the user.

core/java/android/os/storage/IMountService.java

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -489,13 +489,14 @@ public void finishMediaUpdate() throws RemoteException {
489489
* IObbActionListener to inform it of the terminal state of the
490490
* call.
491491
*/
492-
public void mountObb(String filename, String key, IObbActionListener token, int nonce)
493-
throws RemoteException {
492+
public void mountObb(String rawPath, String canonicalPath, String key,
493+
IObbActionListener token, int nonce) throws RemoteException {
494494
Parcel _data = Parcel.obtain();
495495
Parcel _reply = Parcel.obtain();
496496
try {
497497
_data.writeInterfaceToken(DESCRIPTOR);
498-
_data.writeString(filename);
498+
_data.writeString(rawPath);
499+
_data.writeString(canonicalPath);
499500
_data.writeString(key);
500501
_data.writeStrongBinder((token != null ? token.asBinder() : null));
501502
_data.writeInt(nonce);
@@ -514,13 +515,14 @@ public void mountObb(String filename, String key, IObbActionListener token, int
514515
* IObbActionListener to inform it of the terminal state of the
515516
* call.
516517
*/
517-
public void unmountObb(String filename, boolean force, IObbActionListener token,
518-
int nonce) throws RemoteException {
518+
public void unmountObb(
519+
String rawPath, boolean force, IObbActionListener token, int nonce)
520+
throws RemoteException {
519521
Parcel _data = Parcel.obtain();
520522
Parcel _reply = Parcel.obtain();
521523
try {
522524
_data.writeInterfaceToken(DESCRIPTOR);
523-
_data.writeString(filename);
525+
_data.writeString(rawPath);
524526
_data.writeInt((force ? 1 : 0));
525527
_data.writeStrongBinder((token != null ? token.asBinder() : null));
526528
_data.writeInt(nonce);
@@ -536,13 +538,13 @@ public void unmountObb(String filename, boolean force, IObbActionListener token,
536538
* Checks whether the specified Opaque Binary Blob (OBB) is mounted
537539
* somewhere.
538540
*/
539-
public boolean isObbMounted(String filename) throws RemoteException {
541+
public boolean isObbMounted(String rawPath) throws RemoteException {
540542
Parcel _data = Parcel.obtain();
541543
Parcel _reply = Parcel.obtain();
542544
boolean _result;
543545
try {
544546
_data.writeInterfaceToken(DESCRIPTOR);
545-
_data.writeString(filename);
547+
_data.writeString(rawPath);
546548
mRemote.transact(Stub.TRANSACTION_isObbMounted, _data, _reply, 0);
547549
_reply.readException();
548550
_result = 0 != _reply.readInt();
@@ -556,13 +558,13 @@ public boolean isObbMounted(String filename) throws RemoteException {
556558
/**
557559
* Gets the path to the mounted Opaque Binary Blob (OBB).
558560
*/
559-
public String getMountedObbPath(String filename) throws RemoteException {
561+
public String getMountedObbPath(String rawPath) throws RemoteException {
560562
Parcel _data = Parcel.obtain();
561563
Parcel _reply = Parcel.obtain();
562564
String _result;
563565
try {
564566
_data.writeInterfaceToken(DESCRIPTOR);
565-
_data.writeString(filename);
567+
_data.writeString(rawPath);
566568
mRemote.transact(Stub.TRANSACTION_getMountedObbPath, _data, _reply, 0);
567569
_reply.readException();
568570
_result = _reply.readString();
@@ -1042,15 +1044,14 @@ public boolean onTransact(int code, Parcel data, Parcel reply,
10421044
}
10431045
case TRANSACTION_mountObb: {
10441046
data.enforceInterface(DESCRIPTOR);
1045-
String filename;
1046-
filename = data.readString();
1047-
String key;
1048-
key = data.readString();
1047+
final String rawPath = data.readString();
1048+
final String canonicalPath = data.readString();
1049+
final String key = data.readString();
10491050
IObbActionListener observer;
10501051
observer = IObbActionListener.Stub.asInterface(data.readStrongBinder());
10511052
int nonce;
10521053
nonce = data.readInt();
1053-
mountObb(filename, key, observer, nonce);
1054+
mountObb(rawPath, canonicalPath, key, observer, nonce);
10541055
reply.writeNoException();
10551056
return true;
10561057
}
@@ -1194,7 +1195,7 @@ public int createSecureContainer(String id, int sizeMb, String fstype, String ke
11941195
/**
11951196
* Gets the path to the mounted Opaque Binary Blob (OBB).
11961197
*/
1197-
public String getMountedObbPath(String filename) throws RemoteException;
1198+
public String getMountedObbPath(String rawPath) throws RemoteException;
11981199

11991200
/**
12001201
* Gets an Array of currently known secure container IDs
@@ -1220,7 +1221,7 @@ public int createSecureContainer(String id, int sizeMb, String fstype, String ke
12201221
* Checks whether the specified Opaque Binary Blob (OBB) is mounted
12211222
* somewhere.
12221223
*/
1223-
public boolean isObbMounted(String filename) throws RemoteException;
1224+
public boolean isObbMounted(String rawPath) throws RemoteException;
12241225

12251226
/*
12261227
* Returns true if the specified container is mounted
@@ -1243,8 +1244,8 @@ public int createSecureContainer(String id, int sizeMb, String fstype, String ke
12431244
* MountService will call back to the supplied IObbActionListener to inform
12441245
* it of the terminal state of the call.
12451246
*/
1246-
public void mountObb(String filename, String key, IObbActionListener token, int nonce)
1247-
throws RemoteException;
1247+
public void mountObb(String rawPath, String canonicalPath, String key,
1248+
IObbActionListener token, int nonce) throws RemoteException;
12481249

12491250
/*
12501251
* Mount a secure container with the specified key and owner UID. Returns an
@@ -1287,7 +1288,7 @@ public void mountObb(String filename, String key, IObbActionListener token, int
12871288
* MountService will call back to the supplied IObbActionListener to inform
12881289
* it of the terminal state of the call.
12891290
*/
1290-
public void unmountObb(String filename, boolean force, IObbActionListener token, int nonce)
1291+
public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce)
12911292
throws RemoteException;
12921293

12931294
/*

core/java/android/os/storage/StorageManager.java

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
import android.util.Log;
2929
import android.util.SparseArray;
3030

31+
import com.android.internal.util.Preconditions;
32+
33+
import java.io.File;
34+
import java.io.IOException;
3135
import java.lang.ref.WeakReference;
3236
import java.util.ArrayList;
3337
import java.util.List;
@@ -443,25 +447,23 @@ public boolean isUsbMassStorageEnabled() {
443447
* That is, shared UID applications can attempt to mount any other
444448
* application's OBB that shares its UID.
445449
*
446-
* @param filename the path to the OBB file
450+
* @param rawPath the path to the OBB file
447451
* @param key secret used to encrypt the OBB; may be <code>null</code> if no
448452
* encryption was used on the OBB.
449453
* @param listener will receive the success or failure of the operation
450454
* @return whether the mount call was successfully queued or not
451455
*/
452-
public boolean mountObb(String filename, String key, OnObbStateChangeListener listener) {
453-
if (filename == null) {
454-
throw new IllegalArgumentException("filename cannot be null");
455-
}
456-
457-
if (listener == null) {
458-
throw new IllegalArgumentException("listener cannot be null");
459-
}
456+
public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) {
457+
Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
458+
Preconditions.checkNotNull(listener, "listener cannot be null");
460459

461460
try {
461+
final String canonicalPath = new File(rawPath).getCanonicalPath();
462462
final int nonce = mObbActionListener.addListener(listener);
463-
mMountService.mountObb(filename, key, mObbActionListener, nonce);
463+
mMountService.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce);
464464
return true;
465+
} catch (IOException e) {
466+
throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
465467
} catch (RemoteException e) {
466468
Log.e(TAG, "Failed to mount OBB", e);
467469
}
@@ -483,24 +485,19 @@ public boolean mountObb(String filename, String key, OnObbStateChangeListener li
483485
* application's OBB that shares its UID.
484486
* <p>
485487
*
486-
* @param filename path to the OBB file
488+
* @param rawPath path to the OBB file
487489
* @param force whether to kill any programs using this in order to unmount
488490
* it
489491
* @param listener will receive the success or failure of the operation
490492
* @return whether the unmount call was successfully queued or not
491493
*/
492-
public boolean unmountObb(String filename, boolean force, OnObbStateChangeListener listener) {
493-
if (filename == null) {
494-
throw new IllegalArgumentException("filename cannot be null");
495-
}
496-
497-
if (listener == null) {
498-
throw new IllegalArgumentException("listener cannot be null");
499-
}
494+
public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) {
495+
Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
496+
Preconditions.checkNotNull(listener, "listener cannot be null");
500497

501498
try {
502499
final int nonce = mObbActionListener.addListener(listener);
503-
mMountService.unmountObb(filename, force, mObbActionListener, nonce);
500+
mMountService.unmountObb(rawPath, force, mObbActionListener, nonce);
504501
return true;
505502
} catch (RemoteException e) {
506503
Log.e(TAG, "Failed to mount OBB", e);
@@ -512,16 +509,14 @@ public boolean unmountObb(String filename, boolean force, OnObbStateChangeListen
512509
/**
513510
* Check whether an Opaque Binary Blob (OBB) is mounted or not.
514511
*
515-
* @param filename path to OBB image
512+
* @param rawPath path to OBB image
516513
* @return true if OBB is mounted; false if not mounted or on error
517514
*/
518-
public boolean isObbMounted(String filename) {
519-
if (filename == null) {
520-
throw new IllegalArgumentException("filename cannot be null");
521-
}
515+
public boolean isObbMounted(String rawPath) {
516+
Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
522517

523518
try {
524-
return mMountService.isObbMounted(filename);
519+
return mMountService.isObbMounted(rawPath);
525520
} catch (RemoteException e) {
526521
Log.e(TAG, "Failed to check if OBB is mounted", e);
527522
}
@@ -534,17 +529,15 @@ public boolean isObbMounted(String filename) {
534529
* give you the path to where you can obtain access to the internals of the
535530
* OBB.
536531
*
537-
* @param filename path to OBB image
532+
* @param rawPath path to OBB image
538533
* @return absolute path to mounted OBB image data or <code>null</code> if
539534
* not mounted or exception encountered trying to read status
540535
*/
541-
public String getMountedObbPath(String filename) {
542-
if (filename == null) {
543-
throw new IllegalArgumentException("filename cannot be null");
544-
}
536+
public String getMountedObbPath(String rawPath) {
537+
Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
545538

546539
try {
547-
return mMountService.getMountedObbPath(filename);
540+
return mMountService.getMountedObbPath(rawPath);
548541
} catch (RemoteException e) {
549542
Log.e(TAG, "Failed to find mounted path for OBB", e);
550543
}

include/storage/IMountService.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include <storage/IMountShutdownObserver.h>
2222
#include <storage/IObbActionListener.h>
2323

24+
#include <utils/String8.h>
25+
2426
#include <binder/IInterface.h>
2527
#include <binder/Parcel.h>
2628

@@ -60,8 +62,9 @@ class IMountService: public IInterface {
6062
String16*& containers) = 0;
6163
virtual void shutdown(const sp<IMountShutdownObserver>& observer) = 0;
6264
virtual void finishMediaUpdate() = 0;
63-
virtual void mountObb(const String16& filename, const String16& key,
64-
const sp<IObbActionListener>& token, const int32_t nonce) = 0;
65+
virtual void mountObb(const String16& rawPath, const String16& canonicalPath,
66+
const String16& key, const sp<IObbActionListener>& token,
67+
const int32_t nonce) = 0;
6568
virtual void unmountObb(const String16& filename, const bool force,
6669
const sp<IObbActionListener>& token, const int32_t nonce) = 0;
6770
virtual bool isObbMounted(const String16& filename) = 0;

libs/storage/IMountService.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,12 +433,13 @@ class BpMountService: public BpInterface<IMountService>
433433
reply.readExceptionCode();
434434
}
435435

436-
void mountObb(const String16& filename, const String16& key,
436+
void mountObb(const String16& rawPath, const String16& canonicalPath, const String16& key,
437437
const sp<IObbActionListener>& token, int32_t nonce)
438438
{
439439
Parcel data, reply;
440440
data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
441-
data.writeString16(filename);
441+
data.writeString16(rawPath);
442+
data.writeString16(canonicalPath);
442443
data.writeString16(key);
443444
data.writeStrongBinder(token->asBinder());
444445
data.writeInt32(nonce);

native/android/storage_manager.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,20 @@ struct AStorageManager : public RefBase {
125125
}
126126
}
127127

128-
void mountObb(const char* filename, const char* key, AStorageManager_obbCallbackFunc func, void* data) {
128+
void mountObb(const char* rawPath, const char* key, AStorageManager_obbCallbackFunc func,
129+
void* data) {
130+
// Resolve path before sending to MountService
131+
char canonicalPath[PATH_MAX];
132+
if (realpath(rawPath, canonicalPath) == NULL) {
133+
ALOGE("mountObb failed to resolve path %s: %s", rawPath, strerror(errno));
134+
return;
135+
}
136+
129137
ObbCallback* cb = registerObbCallback(func, data);
130-
String16 filename16(filename);
138+
String16 rawPath16(rawPath);
139+
String16 canonicalPath16(canonicalPath);
131140
String16 key16(key);
132-
mMountService->mountObb(filename16, key16, mObbActionListener, cb->nonce);
141+
mMountService->mountObb(rawPath16, canonicalPath16, key16, mObbActionListener, cb->nonce);
133142
}
134143

135144
void unmountObb(const char* filename, const bool force, AStorageManager_obbCallbackFunc func, void* data) {

0 commit comments

Comments
 (0)