blob: d6e23fb3ce3937f390a7500a7b25eb474e75cbf3 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.content.pm.PackageManager;
24import android.content.res.Resources;
25import android.net.Uri;
San Mehatb1043402010-02-05 08:26:50 -080026import android.os.storage.IMountService;
27import android.os.storage.IMountServiceListener;
28import android.os.storage.StorageResultCode;
San Mehat4270e1e2010-01-29 05:32:19 -080029import android.os.RemoteException;
30import android.os.IBinder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.os.Environment;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -080032import android.os.ServiceManager;
San Mehat207e5382010-02-04 20:46:54 -080033import android.os.SystemClock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.os.SystemProperties;
35import android.os.UEventObserver;
San Mehat1f6301e2010-01-07 22:40:27 -080036import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.text.TextUtils;
38import android.util.Log;
San Mehat22dd86e2010-01-12 12:21:18 -080039import java.util.ArrayList;
San Mehat6cdd9c02010-02-09 14:45:20 -080040import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
42import java.io.File;
43import java.io.FileReader;
44
45/**
San Mehatb1043402010-02-05 08:26:50 -080046 * MountService implements back-end services for platform storage
47 * management.
48 * @hide - Applications should use android.os.storage.StorageManager
49 * to access the MountService.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 */
San Mehat22dd86e2010-01-12 12:21:18 -080051class MountService extends IMountService.Stub
52 implements INativeDaemonConnectorCallbacks {
San Mehatb1043402010-02-05 08:26:50 -080053 private static final boolean LOCAL_LOGD = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054
55 private static final String TAG = "MountService";
56
San Mehat4270e1e2010-01-29 05:32:19 -080057 /*
58 * Internal vold volume state constants
59 */
San Mehat7fd0fee2009-12-17 07:12:23 -080060 class VolumeState {
61 public static final int Init = -1;
62 public static final int NoMedia = 0;
63 public static final int Idle = 1;
64 public static final int Pending = 2;
65 public static final int Checking = 3;
66 public static final int Mounted = 4;
67 public static final int Unmounting = 5;
68 public static final int Formatting = 6;
69 public static final int Shared = 7;
70 public static final int SharedMnt = 8;
71 }
72
San Mehat4270e1e2010-01-29 05:32:19 -080073 /*
74 * Internal vold response code constants
75 */
San Mehat22dd86e2010-01-12 12:21:18 -080076 class VoldResponseCode {
San Mehat4270e1e2010-01-29 05:32:19 -080077 /*
78 * 100 series - Requestion action was initiated; expect another reply
79 * before proceeding with a new command.
80 */
San Mehat22dd86e2010-01-12 12:21:18 -080081 public static final int VolumeListResult = 110;
82 public static final int AsecListResult = 111;
San Mehatc1b4ce92010-02-16 17:13:03 -080083 public static final int StorageUsersListResult = 112;
San Mehat22dd86e2010-01-12 12:21:18 -080084
San Mehat4270e1e2010-01-29 05:32:19 -080085 /*
86 * 200 series - Requestion action has been successfully completed.
87 */
88 public static final int ShareStatusResult = 210;
San Mehat22dd86e2010-01-12 12:21:18 -080089 public static final int AsecPathResult = 211;
San Mehat4270e1e2010-01-29 05:32:19 -080090 public static final int ShareEnabledResult = 212;
San Mehat22dd86e2010-01-12 12:21:18 -080091
San Mehat4270e1e2010-01-29 05:32:19 -080092 /*
93 * 400 series - Command was accepted, but the requested action
94 * did not take place.
95 */
96 public static final int OpFailedNoMedia = 401;
97 public static final int OpFailedMediaBlank = 402;
98 public static final int OpFailedMediaCorrupt = 403;
99 public static final int OpFailedVolNotMounted = 404;
San Mehatd9709982010-02-18 11:43:03 -0800100 public static final int OpFailedStorageBusy = 405;
San Mehat4270e1e2010-01-29 05:32:19 -0800101
102 /*
103 * 600 series - Unsolicited broadcasts.
104 */
San Mehat22dd86e2010-01-12 12:21:18 -0800105 public static final int VolumeStateChange = 605;
San Mehat22dd86e2010-01-12 12:21:18 -0800106 public static final int ShareAvailabilityChange = 620;
107 public static final int VolumeDiskInserted = 630;
108 public static final int VolumeDiskRemoved = 631;
109 public static final int VolumeBadRemoval = 632;
110 }
111
San Mehat4270e1e2010-01-29 05:32:19 -0800112 private Context mContext;
113 private NativeDaemonConnector mConnector;
114 private String mLegacyState = Environment.MEDIA_REMOVED;
115 private PackageManagerService mPms;
116 private boolean mUmsEnabling;
117 private ArrayList<MountServiceBinderListener> mListeners;
San Mehat207e5382010-02-04 20:46:54 -0800118 private boolean mBooted;
119 private boolean mReady;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800120
San Mehat6cdd9c02010-02-09 14:45:20 -0800121 /**
122 * Private hash of currently mounted secure containers.
123 */
124 private HashSet<String> mAsecMountSet = new HashSet<String>();
125
San Mehat207e5382010-02-04 20:46:54 -0800126 private void waitForReady() {
127 while (mReady == false) {
128 for (int retries = 5; retries > 0; retries--) {
129 if (mReady) {
130 return;
131 }
132 SystemClock.sleep(1000);
133 }
134 Log.w(TAG, "Waiting too long for mReady!");
135 }
San Mehat1f6301e2010-01-07 22:40:27 -0800136 }
137
San Mehat207e5382010-02-04 20:46:54 -0800138 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 public void onReceive(Context context, Intent intent) {
San Mehat91c77612010-01-07 10:39:41 -0800140 String action = intent.getAction();
141
142 if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
San Mehat207e5382010-02-04 20:46:54 -0800143 mBooted = true;
San Mehat22dd86e2010-01-12 12:21:18 -0800144
Marco Nelissenc34ebce2010-02-18 13:39:41 -0800145 /*
146 * In the simulator, we need to broadcast a volume mounted event
147 * to make the media scanner run.
148 */
149 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
150 notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia, VolumeState.Mounted);
151 return;
152 }
San Mehat207e5382010-02-04 20:46:54 -0800153 String path = Environment.getExternalStorageDirectory().getPath();
154 if (getVolumeState(path).equals(Environment.MEDIA_UNMOUNTED)) {
155 int rc = doMountVolume(path);
San Mehatb1043402010-02-05 08:26:50 -0800156 if (rc != StorageResultCode.OperationSucceeded) {
San Mehat207e5382010-02-04 20:46:54 -0800157 Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
158 }
159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 }
161 }
162 };
163
San Mehat4270e1e2010-01-29 05:32:19 -0800164 private final class MountServiceBinderListener implements IBinder.DeathRecipient {
165 final IMountServiceListener mListener;
166
167 MountServiceBinderListener(IMountServiceListener listener) {
168 mListener = listener;
169
San Mehat91c77612010-01-07 10:39:41 -0800170 }
171
San Mehat4270e1e2010-01-29 05:32:19 -0800172 public void binderDied() {
San Mehatb1043402010-02-05 08:26:50 -0800173 if (LOCAL_LOGD) Log.d(TAG, "An IMountServiceListener has died!");
San Mehat4270e1e2010-01-29 05:32:19 -0800174 synchronized(mListeners) {
175 mListeners.remove(this);
176 mListener.asBinder().unlinkToDeath(this, 0);
177 }
178 }
179 }
180
San Mehat207e5382010-02-04 20:46:54 -0800181 private int doShareUnshareVolume(String path, String method, boolean enable) {
San Mehat4270e1e2010-01-29 05:32:19 -0800182 validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
183
184 // TODO: Add support for multiple share methods
185 if (!method.equals("ums")) {
186 throw new IllegalArgumentException(String.format("Method %s not supported", method));
187 }
188
189 /*
190 * If the volume is mounted and we're enabling then unmount it
191 */
192 String vs = getVolumeState(path);
193 if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
San Mehatb1043402010-02-05 08:26:50 -0800194 mUmsEnabling = enable; // Override for isUsbMassStorageEnabled()
San Mehatd9709982010-02-18 11:43:03 -0800195 int rc = doUnmountVolume(path, false);
San Mehatb1043402010-02-05 08:26:50 -0800196 mUmsEnabling = false; // Clear override
San Mehat59443a62010-02-09 13:28:45 -0800197 if (rc != StorageResultCode.OperationSucceeded) {
198 Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc));
199 return rc;
200 }
San Mehat4270e1e2010-01-29 05:32:19 -0800201 }
202
203 try {
204 mConnector.doCommand(String.format(
205 "volume %sshare %s %s", (enable ? "" : "un"), path, method));
206 } catch (NativeDaemonConnectorException e) {
207 Log.e(TAG, "Failed to share/unshare", e);
San Mehatb1043402010-02-05 08:26:50 -0800208 return StorageResultCode.OperationFailedInternalError;
San Mehat4270e1e2010-01-29 05:32:19 -0800209 }
210
211 /*
212 * If we disabled UMS then mount the volume
213 */
214 if (!enable) {
San Mehatb1043402010-02-05 08:26:50 -0800215 if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
San Mehat4270e1e2010-01-29 05:32:19 -0800216 Log.e(TAG, String.format(
217 "Failed to remount %s after disabling share method %s", path, method));
218 /*
219 * Even though the mount failed, the unshare didn't so don't indicate an error.
220 * The mountVolume() call will have set the storage state and sent the necessary
221 * broadcasts.
222 */
223 }
224 }
225
San Mehatb1043402010-02-05 08:26:50 -0800226 return StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800227 }
228
San Mehat207e5382010-02-04 20:46:54 -0800229 private void updatePublicVolumeState(String path, String state) {
San Mehat4270e1e2010-01-29 05:32:19 -0800230 if (!path.equals(Environment.getExternalStorageDirectory().getPath())) {
231 Log.w(TAG, "Multiple volumes not currently supported");
232 return;
233 }
San Mehatb1043402010-02-05 08:26:50 -0800234
235 if (mLegacyState.equals(state)) {
236 Log.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state));
237 return;
238 }
San Mehat4270e1e2010-01-29 05:32:19 -0800239
240 String oldState = mLegacyState;
241 mLegacyState = state;
242
243 synchronized (mListeners) {
244 for (int i = mListeners.size() -1; i >= 0; i--) {
245 MountServiceBinderListener bl = mListeners.get(i);
246 try {
San Mehatb1043402010-02-05 08:26:50 -0800247 bl.mListener.onStorageStateChanged(path, oldState, state);
San Mehat4270e1e2010-01-29 05:32:19 -0800248 } catch (RemoteException rex) {
249 Log.e(TAG, "Listener dead");
250 mListeners.remove(i);
251 } catch (Exception ex) {
252 Log.e(TAG, "Listener failed", ex);
253 }
254 }
255 }
256 }
257
258 /**
259 *
260 * Callback from NativeDaemonConnector
261 */
262 public void onDaemonConnected() {
263 /*
264 * Since we'll be calling back into the NativeDaemonConnector,
265 * we need to do our work in a new thread.
266 */
267 new Thread() {
268 public void run() {
269 /**
270 * Determine media state and UMS detection status
271 */
272 String path = Environment.getExternalStorageDirectory().getPath();
273 String state = Environment.MEDIA_REMOVED;
274
275 try {
276 String[] vols = mConnector.doListCommand(
277 "volume list", VoldResponseCode.VolumeListResult);
278 for (String volstr : vols) {
279 String[] tok = volstr.split(" ");
280 // FMT: <label> <mountpoint> <state>
281 if (!tok[1].equals(path)) {
282 Log.w(TAG, String.format(
283 "Skipping unknown volume '%s'",tok[1]));
284 continue;
285 }
286 int st = Integer.parseInt(tok[2]);
287 if (st == VolumeState.NoMedia) {
288 state = Environment.MEDIA_REMOVED;
289 } else if (st == VolumeState.Idle) {
San Mehat207e5382010-02-04 20:46:54 -0800290 state = Environment.MEDIA_UNMOUNTED;
San Mehat4270e1e2010-01-29 05:32:19 -0800291 } else if (st == VolumeState.Mounted) {
292 state = Environment.MEDIA_MOUNTED;
293 Log.i(TAG, "Media already mounted on daemon connection");
294 } else if (st == VolumeState.Shared) {
295 state = Environment.MEDIA_SHARED;
296 Log.i(TAG, "Media shared on daemon connection");
297 } else {
298 throw new Exception(String.format("Unexpected state %d", st));
299 }
300 }
301 if (state != null) {
302 updatePublicVolumeState(path, state);
303 }
304 } catch (Exception e) {
305 Log.e(TAG, "Error processing initial volume state", e);
306 updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
307 }
308
309 try {
San Mehat207e5382010-02-04 20:46:54 -0800310 boolean avail = doGetShareMethodAvailable("ums");
San Mehat4270e1e2010-01-29 05:32:19 -0800311 notifyShareAvailabilityChange("ums", avail);
312 } catch (Exception ex) {
313 Log.w(TAG, "Failed to get share availability");
314 }
San Mehat207e5382010-02-04 20:46:54 -0800315 /*
316 * Now that we've done our initialization, release
317 * the hounds!
318 */
319 mReady = true;
San Mehat4270e1e2010-01-29 05:32:19 -0800320 }
321 }.start();
322 }
323
324 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800325 * Callback from NativeDaemonConnector
326 */
327 public boolean onEvent(int code, String raw, String[] cooked) {
328 Intent in = null;
329
San Mehat4270e1e2010-01-29 05:32:19 -0800330 if (code == VoldResponseCode.VolumeStateChange) {
331 /*
332 * One of the volumes we're managing has changed state.
333 * Format: "NNN Volume <label> <path> state changed
334 * from <old_#> (<old_str>) to <new_#> (<new_str>)"
335 */
336 notifyVolumeStateChange(
337 cooked[2], cooked[3], Integer.parseInt(cooked[7]),
338 Integer.parseInt(cooked[10]));
339 } else if (code == VoldResponseCode.ShareAvailabilityChange) {
340 // FMT: NNN Share method <method> now <available|unavailable>
341 boolean avail = false;
342 if (cooked[5].equals("available")) {
343 avail = true;
344 }
345 notifyShareAvailabilityChange(cooked[3], avail);
346 } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
347 (code == VoldResponseCode.VolumeDiskRemoved) ||
348 (code == VoldResponseCode.VolumeBadRemoval)) {
349 // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
350 // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
351 // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
352 final String label = cooked[2];
353 final String path = cooked[3];
354 int major = -1;
355 int minor = -1;
356
357 try {
358 String devComp = cooked[6].substring(1, cooked[6].length() -1);
359 String[] devTok = devComp.split(":");
360 major = Integer.parseInt(devTok[0]);
361 minor = Integer.parseInt(devTok[1]);
362 } catch (Exception ex) {
363 Log.e(TAG, "Failed to parse major/minor", ex);
364 }
365
San Mehat4270e1e2010-01-29 05:32:19 -0800366 if (code == VoldResponseCode.VolumeDiskInserted) {
367 new Thread() {
368 public void run() {
369 try {
370 int rc;
San Mehatb1043402010-02-05 08:26:50 -0800371 if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
San Mehat4270e1e2010-01-29 05:32:19 -0800372 Log.w(TAG, String.format("Insertion mount failed (%d)", rc));
373 }
374 } catch (Exception ex) {
375 Log.w(TAG, "Failed to mount media on insertion", ex);
376 }
377 }
378 }.start();
379 } else if (code == VoldResponseCode.VolumeDiskRemoved) {
380 /*
381 * This event gets trumped if we're already in BAD_REMOVAL state
382 */
383 if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
384 return true;
385 }
386 /* Send the media unmounted event first */
387 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
388 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
389 mContext.sendBroadcast(in);
390
391 updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
392 in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path));
393 } else if (code == VoldResponseCode.VolumeBadRemoval) {
394 /* Send the media unmounted event first */
395 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
396 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
397 mContext.sendBroadcast(in);
398
399 updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
400 in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path));
401 } else {
402 Log.e(TAG, String.format("Unknown code {%d}", code));
403 }
404 } else {
405 return false;
406 }
407
408 if (in != null) {
409 mContext.sendBroadcast(in);
410 }
411 return true;
412 }
413
San Mehat207e5382010-02-04 20:46:54 -0800414 private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
San Mehat4270e1e2010-01-29 05:32:19 -0800415 String vs = getVolumeState(path);
416
417 Intent in = null;
418
419 if (newState == VolumeState.Init) {
420 } else if (newState == VolumeState.NoMedia) {
421 // NoMedia is handled via Disk Remove events
422 } else if (newState == VolumeState.Idle) {
423 /*
424 * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
425 * if we're in the process of enabling UMS
426 */
427 if (!vs.equals(
428 Environment.MEDIA_BAD_REMOVAL) && !vs.equals(
429 Environment.MEDIA_NOFS) && !vs.equals(
430 Environment.MEDIA_UNMOUNTABLE) && !mUmsEnabling) {
431 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
432 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
433 }
434 } else if (newState == VolumeState.Pending) {
435 } else if (newState == VolumeState.Checking) {
436 updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
437 in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path));
438 } else if (newState == VolumeState.Mounted) {
439 updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
440 // Update media status on PackageManagerService to mount packages on sdcard
441 mPms.updateExternalMediaStatus(true);
442 in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path));
443 in.putExtra("read-only", false);
444 } else if (newState == VolumeState.Unmounting) {
445 mPms.updateExternalMediaStatus(false);
446 in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path));
447 } else if (newState == VolumeState.Formatting) {
448 } else if (newState == VolumeState.Shared) {
449 /* Send the media unmounted event first */
450 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
451 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
452 mContext.sendBroadcast(in);
453
454 updatePublicVolumeState(path, Environment.MEDIA_SHARED);
455 in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path));
456 } else if (newState == VolumeState.SharedMnt) {
457 Log.e(TAG, "Live shared mounts not supported yet!");
458 return;
459 } else {
460 Log.e(TAG, "Unhandled VolumeState {" + newState + "}");
461 }
462
463 if (in != null) {
464 mContext.sendBroadcast(in);
465 }
466 }
467
San Mehat207e5382010-02-04 20:46:54 -0800468 private boolean doGetShareMethodAvailable(String method) {
469 ArrayList<String> rsp = mConnector.doCommand("share status " + method);
470
471 for (String line : rsp) {
472 String []tok = line.split(" ");
473 int code;
474 try {
475 code = Integer.parseInt(tok[0]);
476 } catch (NumberFormatException nfe) {
477 Log.e(TAG, String.format("Error parsing code %s", tok[0]));
478 return false;
479 }
480 if (code == VoldResponseCode.ShareStatusResult) {
481 if (tok[2].equals("available"))
482 return true;
483 return false;
484 } else {
485 Log.e(TAG, String.format("Unexpected response code %d", code));
486 return false;
487 }
488 }
489 Log.e(TAG, "Got an empty response");
490 return false;
491 }
492
493 private int doMountVolume(String path) {
San Mehatb1043402010-02-05 08:26:50 -0800494 int rc = StorageResultCode.OperationSucceeded;
San Mehat207e5382010-02-04 20:46:54 -0800495
496 try {
497 mConnector.doCommand(String.format("volume mount %s", path));
498 } catch (NativeDaemonConnectorException e) {
499 /*
500 * Mount failed for some reason
501 */
502 Intent in = null;
503 int code = e.getCode();
504 if (code == VoldResponseCode.OpFailedNoMedia) {
505 /*
506 * Attempt to mount but no media inserted
507 */
San Mehatb1043402010-02-05 08:26:50 -0800508 rc = StorageResultCode.OperationFailedNoMedia;
San Mehat207e5382010-02-04 20:46:54 -0800509 } else if (code == VoldResponseCode.OpFailedMediaBlank) {
510 /*
511 * Media is blank or does not contain a supported filesystem
512 */
513 updatePublicVolumeState(path, Environment.MEDIA_NOFS);
514 in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path));
San Mehatb1043402010-02-05 08:26:50 -0800515 rc = StorageResultCode.OperationFailedMediaBlank;
San Mehat207e5382010-02-04 20:46:54 -0800516 } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
517 /*
518 * Volume consistency check failed
519 */
520 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
521 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path));
San Mehatb1043402010-02-05 08:26:50 -0800522 rc = StorageResultCode.OperationFailedMediaCorrupt;
San Mehat207e5382010-02-04 20:46:54 -0800523 } else {
San Mehatb1043402010-02-05 08:26:50 -0800524 rc = StorageResultCode.OperationFailedInternalError;
San Mehat207e5382010-02-04 20:46:54 -0800525 }
526
527 /*
528 * Send broadcast intent (if required for the failure)
529 */
530 if (in != null) {
531 mContext.sendBroadcast(in);
532 }
533 }
534
535 return rc;
536 }
537
San Mehatd9709982010-02-18 11:43:03 -0800538 private int doUnmountVolume(String path, boolean force) {
San Mehat59443a62010-02-09 13:28:45 -0800539 if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
San Mehat207e5382010-02-04 20:46:54 -0800540 return VoldResponseCode.OpFailedVolNotMounted;
541 }
542
543 // Notify PackageManager of potential media removal and deal with
544 // return code later on. The caller of this api should be aware or have been
545 // notified that the applications installed on the media will be killed.
546 mPms.updateExternalMediaStatus(false);
547 try {
San Mehatd9709982010-02-18 11:43:03 -0800548 mConnector.doCommand(String.format(
549 "volume unmount %s%s", path, (force ? " force" : "")));
San Mehatb1043402010-02-05 08:26:50 -0800550 return StorageResultCode.OperationSucceeded;
San Mehat207e5382010-02-04 20:46:54 -0800551 } catch (NativeDaemonConnectorException e) {
552 // Don't worry about mismatch in PackageManager since the
553 // call back will handle the status changes any way.
554 int code = e.getCode();
555 if (code == VoldResponseCode.OpFailedVolNotMounted) {
San Mehata181b212010-02-11 06:50:20 -0800556 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehatd9709982010-02-18 11:43:03 -0800557 } else if (code == VoldResponseCode.OpFailedStorageBusy) {
558 return StorageResultCode.OperationFailedStorageBusy;
San Mehat207e5382010-02-04 20:46:54 -0800559 } else {
San Mehatb1043402010-02-05 08:26:50 -0800560 return StorageResultCode.OperationFailedInternalError;
San Mehat207e5382010-02-04 20:46:54 -0800561 }
562 }
563 }
564
565 private int doFormatVolume(String path) {
566 try {
567 String cmd = String.format("volume format %s", path);
568 mConnector.doCommand(cmd);
San Mehatb1043402010-02-05 08:26:50 -0800569 return StorageResultCode.OperationSucceeded;
San Mehat207e5382010-02-04 20:46:54 -0800570 } catch (NativeDaemonConnectorException e) {
571 int code = e.getCode();
572 if (code == VoldResponseCode.OpFailedNoMedia) {
San Mehatb1043402010-02-05 08:26:50 -0800573 return StorageResultCode.OperationFailedNoMedia;
San Mehat207e5382010-02-04 20:46:54 -0800574 } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
San Mehatb1043402010-02-05 08:26:50 -0800575 return StorageResultCode.OperationFailedMediaCorrupt;
San Mehat207e5382010-02-04 20:46:54 -0800576 } else {
San Mehatb1043402010-02-05 08:26:50 -0800577 return StorageResultCode.OperationFailedInternalError;
San Mehat207e5382010-02-04 20:46:54 -0800578 }
579 }
580 }
581
San Mehatb1043402010-02-05 08:26:50 -0800582 private boolean doGetVolumeShared(String path, String method) {
583 String cmd = String.format("volume shared %s %s", path, method);
584 ArrayList<String> rsp = mConnector.doCommand(cmd);
585
586 for (String line : rsp) {
587 String []tok = line.split(" ");
588 int code;
589 try {
590 code = Integer.parseInt(tok[0]);
591 } catch (NumberFormatException nfe) {
592 Log.e(TAG, String.format("Error parsing code %s", tok[0]));
593 return false;
594 }
595 if (code == VoldResponseCode.ShareEnabledResult) {
596 if (tok[2].equals("enabled"))
597 return true;
598 return false;
599 } else {
600 Log.e(TAG, String.format("Unexpected response code %d", code));
601 return false;
602 }
603 }
604 Log.e(TAG, "Got an empty response");
605 return false;
606 }
607
San Mehat207e5382010-02-04 20:46:54 -0800608 private void notifyShareAvailabilityChange(String method, final boolean avail) {
San Mehat4270e1e2010-01-29 05:32:19 -0800609 if (!method.equals("ums")) {
610 Log.w(TAG, "Ignoring unsupported share method {" + method + "}");
611 return;
612 }
613
614 synchronized (mListeners) {
615 for (int i = mListeners.size() -1; i >= 0; i--) {
616 MountServiceBinderListener bl = mListeners.get(i);
617 try {
San Mehatb1043402010-02-05 08:26:50 -0800618 bl.mListener.onUsbMassStorageConnectionChanged(avail);
San Mehat4270e1e2010-01-29 05:32:19 -0800619 } catch (RemoteException rex) {
620 Log.e(TAG, "Listener dead");
621 mListeners.remove(i);
622 } catch (Exception ex) {
623 Log.e(TAG, "Listener failed", ex);
624 }
625 }
626 }
627
San Mehat207e5382010-02-04 20:46:54 -0800628 if (mBooted == true) {
629 Intent intent;
630 if (avail) {
631 intent = new Intent(Intent.ACTION_UMS_CONNECTED);
632 } else {
633 intent = new Intent(Intent.ACTION_UMS_DISCONNECTED);
634 }
635 mContext.sendBroadcast(intent);
San Mehat4270e1e2010-01-29 05:32:19 -0800636 }
San Mehat4270e1e2010-01-29 05:32:19 -0800637 }
638
San Mehat207e5382010-02-04 20:46:54 -0800639 private void validatePermission(String perm) {
San Mehat4270e1e2010-01-29 05:32:19 -0800640 if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
641 throw new SecurityException(String.format("Requires %s permission", perm));
642 }
643 }
644
645 /**
San Mehat207e5382010-02-04 20:46:54 -0800646 * Constructs a new MountService instance
647 *
648 * @param context Binder context for this service
649 */
650 public MountService(Context context) {
651 mContext = context;
652
San Mehat207e5382010-02-04 20:46:54 -0800653 // XXX: This will go away soon in favor of IMountServiceObserver
654 mPms = (PackageManagerService) ServiceManager.getService("package");
655
656 mContext.registerReceiver(mBroadcastReceiver,
657 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
658
659 mListeners = new ArrayList<MountServiceBinderListener>();
660
Marco Nelissenc34ebce2010-02-18 13:39:41 -0800661 /*
662 * Vold does not run in the simulator, so pretend the connector thread
663 * ran and did its thing.
664 */
665 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
666 mReady = true;
667 mUmsEnabling = true;
668 return;
669 }
670
San Mehat207e5382010-02-04 20:46:54 -0800671 mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
672 mReady = false;
673 Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
674 thread.start();
675 }
676
677 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800678 * Exposed API calls below here
679 */
680
681 public void registerListener(IMountServiceListener listener) {
682 synchronized (mListeners) {
683 MountServiceBinderListener bl = new MountServiceBinderListener(listener);
684 try {
685 listener.asBinder().linkToDeath(bl, 0);
686 mListeners.add(bl);
687 } catch (RemoteException rex) {
688 Log.e(TAG, "Failed to link to listener death");
689 }
690 }
691 }
692
693 public void unregisterListener(IMountServiceListener listener) {
694 synchronized (mListeners) {
695 for(MountServiceBinderListener bl : mListeners) {
696 if (bl.mListener == listener) {
697 mListeners.remove(mListeners.indexOf(bl));
698 return;
699 }
700 }
701 }
702 }
703
704 public void shutdown() {
705 validatePermission(android.Manifest.permission.SHUTDOWN);
706
707 Log.i(TAG, "Shutting down");
708
709 String path = Environment.getExternalStorageDirectory().getPath();
710 String state = getVolumeState(path);
San Mehat91c77612010-01-07 10:39:41 -0800711
712 if (state.equals(Environment.MEDIA_SHARED)) {
713 /*
714 * If the media is currently shared, unshare it.
715 * XXX: This is still dangerous!. We should not
716 * be rebooting at *all* if UMS is enabled, since
717 * the UMS host could have dirty FAT cache entries
718 * yet to flush.
719 */
San Mehatb1043402010-02-05 08:26:50 -0800720 if (setUsbMassStorageEnabled(false) != StorageResultCode.OperationSucceeded) {
San Mehat4270e1e2010-01-29 05:32:19 -0800721 Log.e(TAG, "UMS disable on shutdown failed");
San Mehat91c77612010-01-07 10:39:41 -0800722 }
723 } else if (state.equals(Environment.MEDIA_CHECKING)) {
724 /*
725 * If the media is being checked, then we need to wait for
726 * it to complete before being able to proceed.
727 */
728 // XXX: @hackbod - Should we disable the ANR timer here?
729 int retries = 30;
730 while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
731 try {
732 Thread.sleep(1000);
733 } catch (InterruptedException iex) {
734 Log.e(TAG, "Interrupted while waiting for media", iex);
735 break;
736 }
737 state = Environment.getExternalStorageState();
738 }
739 if (retries == 0) {
740 Log.e(TAG, "Timed out waiting for media to check");
741 }
742 }
743
744 if (state.equals(Environment.MEDIA_MOUNTED)) {
745 /*
746 * If the media is mounted, then gracefully unmount it.
747 */
San Mehatd9709982010-02-18 11:43:03 -0800748 if (doUnmountVolume(path, true) != StorageResultCode.OperationSucceeded) {
San Mehat4270e1e2010-01-29 05:32:19 -0800749 Log.e(TAG, "Failed to unmount media for shutdown");
750 }
751 }
752 }
753
San Mehatb1043402010-02-05 08:26:50 -0800754 public boolean isUsbMassStorageConnected() {
San Mehat207e5382010-02-04 20:46:54 -0800755 waitForReady();
San Mehat91c77612010-01-07 10:39:41 -0800756
San Mehatb1043402010-02-05 08:26:50 -0800757 if (mUmsEnabling) {
758 return true;
San Mehat7fd0fee2009-12-17 07:12:23 -0800759 }
San Mehatb1043402010-02-05 08:26:50 -0800760 return doGetShareMethodAvailable("ums");
761 }
762
763 public int setUsbMassStorageEnabled(boolean enable) {
764 waitForReady();
765
766 return doShareUnshareVolume(Environment.getExternalStorageDirectory().getPath(), "ums", enable);
767 }
768
769 public boolean isUsbMassStorageEnabled() {
770 waitForReady();
771 return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 }
San Mehat4270e1e2010-01-29 05:32:19 -0800773
San Mehat7fd0fee2009-12-17 07:12:23 -0800774 /**
775 * @return state of the volume at the specified mount point
776 */
San Mehat4270e1e2010-01-29 05:32:19 -0800777 public String getVolumeState(String mountPoint) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800778 /*
779 * XXX: Until we have multiple volume discovery, just hardwire
780 * this to /sdcard
781 */
782 if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
783 Log.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
784 throw new IllegalArgumentException();
785 }
786
787 return mLegacyState;
788 }
789
San Mehat4270e1e2010-01-29 05:32:19 -0800790 public int mountVolume(String path) {
791 validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehat4270e1e2010-01-29 05:32:19 -0800792
San Mehat207e5382010-02-04 20:46:54 -0800793 waitForReady();
794 return doMountVolume(path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 }
796
San Mehatd9709982010-02-18 11:43:03 -0800797 public int unmountVolume(String path, boolean force) {
San Mehat4270e1e2010-01-29 05:32:19 -0800798 validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -0800799 waitForReady();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800
San Mehatd9709982010-02-18 11:43:03 -0800801 return doUnmountVolume(path, force);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 }
803
San Mehat4270e1e2010-01-29 05:32:19 -0800804 public int formatVolume(String path) {
805 validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -0800806 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -0800807
San Mehat207e5382010-02-04 20:46:54 -0800808 return doFormatVolume(path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 }
810
San Mehatc1b4ce92010-02-16 17:13:03 -0800811 public int []getStorageUsers(String path) {
812 validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
813 waitForReady();
814 try {
815 String[] r = mConnector.doListCommand(
816 String.format("storage users %s", path),
817 VoldResponseCode.StorageUsersListResult);
818 // FMT: <pid> <process name>
819 int[] data = new int[r.length];
820 for (int i = 0; i < r.length; i++) {
821 String []tok = r[i].split(" ");
822 try {
823 data[i] = Integer.parseInt(tok[0]);
824 } catch (NumberFormatException nfe) {
825 Log.e(TAG, String.format("Error parsing pid %s", tok[0]));
826 return new int[0];
827 }
828 }
829 return data;
830 } catch (NativeDaemonConnectorException e) {
831 Log.e(TAG, "Failed to retrieve storage users list", e);
832 return new int[0];
833 }
834 }
835
San Mehatb1043402010-02-05 08:26:50 -0800836 private void warnOnNotMounted() {
837 if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
838 Log.w(TAG, "getSecureContainerList() called when storage not mounted");
839 }
840 }
841
San Mehat4270e1e2010-01-29 05:32:19 -0800842 public String[] getSecureContainerList() {
843 validatePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -0800844 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800845 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -0800846
San Mehat4270e1e2010-01-29 05:32:19 -0800847 try {
848 return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult);
849 } catch (NativeDaemonConnectorException e) {
850 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 }
852 }
San Mehat36972292010-01-06 11:06:32 -0800853
San Mehat4270e1e2010-01-29 05:32:19 -0800854 public int createSecureContainer(String id, int sizeMb, String fstype,
855 String key, int ownerUid) {
856 validatePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -0800857 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800858 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800859
San Mehatb1043402010-02-05 08:26:50 -0800860 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800861 String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid);
862 try {
863 mConnector.doCommand(cmd);
864 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -0800865 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -0800866 }
San Mehata181b212010-02-11 06:50:20 -0800867
868 if (rc == StorageResultCode.OperationSucceeded) {
869 synchronized (mAsecMountSet) {
870 mAsecMountSet.add(id);
871 }
872 }
San Mehat4270e1e2010-01-29 05:32:19 -0800873 return rc;
San Mehat36972292010-01-06 11:06:32 -0800874 }
875
San Mehat4270e1e2010-01-29 05:32:19 -0800876 public int finalizeSecureContainer(String id) {
877 validatePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -0800878 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800879
San Mehatb1043402010-02-05 08:26:50 -0800880 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800881 try {
882 mConnector.doCommand(String.format("asec finalize %s", id));
San Mehata181b212010-02-11 06:50:20 -0800883 /*
884 * Finalization does a remount, so no need
885 * to update mAsecMountSet
886 */
San Mehat4270e1e2010-01-29 05:32:19 -0800887 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -0800888 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -0800889 }
San Mehat4270e1e2010-01-29 05:32:19 -0800890 return rc;
San Mehat36972292010-01-06 11:06:32 -0800891 }
892
San Mehatd9709982010-02-18 11:43:03 -0800893 public int destroySecureContainer(String id, boolean force) {
San Mehat4270e1e2010-01-29 05:32:19 -0800894 validatePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -0800895 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800896 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -0800897
San Mehatb1043402010-02-05 08:26:50 -0800898 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800899 try {
San Mehatd9709982010-02-18 11:43:03 -0800900 mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
San Mehat4270e1e2010-01-29 05:32:19 -0800901 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -0800902 int code = e.getCode();
903 if (code == VoldResponseCode.OpFailedStorageBusy) {
904 rc = StorageResultCode.OperationFailedStorageBusy;
905 } else {
906 rc = StorageResultCode.OperationFailedInternalError;
907 }
San Mehat02735bc2010-01-26 15:18:08 -0800908 }
San Mehata181b212010-02-11 06:50:20 -0800909
910 if (rc == StorageResultCode.OperationSucceeded) {
911 synchronized (mAsecMountSet) {
912 if (mAsecMountSet.contains(id)) {
913 mAsecMountSet.remove(id);
914 }
915 }
916 }
917
San Mehat4270e1e2010-01-29 05:32:19 -0800918 return rc;
San Mehat36972292010-01-06 11:06:32 -0800919 }
920
San Mehat4270e1e2010-01-29 05:32:19 -0800921 public int mountSecureContainer(String id, String key, int ownerUid) {
922 validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -0800923 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800924 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800925
San Mehata181b212010-02-11 06:50:20 -0800926 synchronized (mAsecMountSet) {
927 if (mAsecMountSet.contains(id)) {
928 return StorageResultCode.OperationFailedStorageMounted;
929 }
930 }
931
San Mehatb1043402010-02-05 08:26:50 -0800932 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800933 String cmd = String.format("asec mount %s %s %d", id, key, ownerUid);
934 try {
935 mConnector.doCommand(cmd);
936 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -0800937 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -0800938 }
San Mehat6cdd9c02010-02-09 14:45:20 -0800939
940 if (rc == StorageResultCode.OperationSucceeded) {
941 synchronized (mAsecMountSet) {
942 mAsecMountSet.add(id);
943 }
944 }
San Mehat4270e1e2010-01-29 05:32:19 -0800945 return rc;
San Mehat36972292010-01-06 11:06:32 -0800946 }
947
San Mehatd9709982010-02-18 11:43:03 -0800948 public int unmountSecureContainer(String id, boolean force) {
San Mehat4270e1e2010-01-29 05:32:19 -0800949 validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -0800950 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800951 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800952
San Mehat6cdd9c02010-02-09 14:45:20 -0800953 synchronized (mAsecMountSet) {
954 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -0800955 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -0800956 }
957 }
958
San Mehatb1043402010-02-05 08:26:50 -0800959 int rc = StorageResultCode.OperationSucceeded;
San Mehatd9709982010-02-18 11:43:03 -0800960 String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
San Mehat4270e1e2010-01-29 05:32:19 -0800961 try {
962 mConnector.doCommand(cmd);
963 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -0800964 int code = e.getCode();
965 if (code == VoldResponseCode.OpFailedStorageBusy) {
966 rc = StorageResultCode.OperationFailedStorageBusy;
967 } else {
968 rc = StorageResultCode.OperationFailedInternalError;
969 }
San Mehat02735bc2010-01-26 15:18:08 -0800970 }
San Mehat6cdd9c02010-02-09 14:45:20 -0800971
972 if (rc == StorageResultCode.OperationSucceeded) {
973 synchronized (mAsecMountSet) {
974 mAsecMountSet.remove(id);
975 }
976 }
San Mehat4270e1e2010-01-29 05:32:19 -0800977 return rc;
San Mehat9dba7092010-01-18 06:47:41 -0800978 }
979
San Mehat6cdd9c02010-02-09 14:45:20 -0800980 public boolean isSecureContainerMounted(String id) {
981 validatePermission(android.Manifest.permission.ASEC_ACCESS);
982 waitForReady();
983 warnOnNotMounted();
984
985 synchronized (mAsecMountSet) {
986 return mAsecMountSet.contains(id);
987 }
988 }
989
San Mehat4270e1e2010-01-29 05:32:19 -0800990 public int renameSecureContainer(String oldId, String newId) {
991 validatePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -0800992 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800993 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800994
San Mehata181b212010-02-11 06:50:20 -0800995 synchronized (mAsecMountSet) {
996 if (mAsecMountSet.contains(oldId)) {
997 return StorageResultCode.OperationFailedStorageMounted;
998 }
999 }
1000
San Mehatb1043402010-02-05 08:26:50 -08001001 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08001002 String cmd = String.format("asec rename %s %s", oldId, newId);
1003 try {
1004 mConnector.doCommand(cmd);
1005 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08001006 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08001007 }
San Mehata181b212010-02-11 06:50:20 -08001008
San Mehat4270e1e2010-01-29 05:32:19 -08001009 return rc;
San Mehat45f61042010-01-23 08:12:43 -08001010 }
1011
San Mehat4270e1e2010-01-29 05:32:19 -08001012 public String getSecureContainerPath(String id) {
1013 validatePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08001014 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001015 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08001016
San Mehat4270e1e2010-01-29 05:32:19 -08001017 ArrayList<String> rsp = mConnector.doCommand("asec path " + id);
San Mehat36972292010-01-06 11:06:32 -08001018
San Mehat22dd86e2010-01-12 12:21:18 -08001019 for (String line : rsp) {
1020 String []tok = line.split(" ");
1021 int code = Integer.parseInt(tok[0]);
1022 if (code == VoldResponseCode.AsecPathResult) {
1023 return tok[1];
1024 } else {
San Mehat4270e1e2010-01-29 05:32:19 -08001025 Log.e(TAG, String.format("Unexpected response code %d", code));
1026 return "";
San Mehat22dd86e2010-01-12 12:21:18 -08001027 }
1028 }
San Mehat4270e1e2010-01-29 05:32:19 -08001029
1030 Log.e(TAG, "Got an empty response");
1031 return "";
San Mehat22dd86e2010-01-12 12:21:18 -08001032 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033}
1034