blob: fb17538f67775253a7603c2557071370c65abed0 [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 Mehat6a965af22010-02-24 17:47:30 -0800118 private boolean mBooted = false;
119 private boolean mReady = false;
120 private boolean mSendUmsConnectedOnBoot = false;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800121
San Mehat6cdd9c02010-02-09 14:45:20 -0800122 /**
123 * Private hash of currently mounted secure containers.
124 */
125 private HashSet<String> mAsecMountSet = new HashSet<String>();
126
San Mehat207e5382010-02-04 20:46:54 -0800127 private void waitForReady() {
128 while (mReady == false) {
129 for (int retries = 5; retries > 0; retries--) {
130 if (mReady) {
131 return;
132 }
133 SystemClock.sleep(1000);
134 }
135 Log.w(TAG, "Waiting too long for mReady!");
136 }
San Mehat1f6301e2010-01-07 22:40:27 -0800137 }
138
San Mehat207e5382010-02-04 20:46:54 -0800139 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 public void onReceive(Context context, Intent intent) {
San Mehat91c77612010-01-07 10:39:41 -0800141 String action = intent.getAction();
142
143 if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
San Mehat207e5382010-02-04 20:46:54 -0800144 mBooted = true;
San Mehat22dd86e2010-01-12 12:21:18 -0800145
Marco Nelissenc34ebce2010-02-18 13:39:41 -0800146 /*
147 * In the simulator, we need to broadcast a volume mounted event
148 * to make the media scanner run.
149 */
150 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
151 notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia, VolumeState.Mounted);
152 return;
153 }
San Mehatfafb0412010-02-18 19:40:04 -0800154 new Thread() {
155 public void run() {
156 try {
157 String path = Environment.getExternalStorageDirectory().getPath();
158 if (getVolumeState(
159 Environment.getExternalStorageDirectory().getPath()).equals(
160 Environment.MEDIA_UNMOUNTED)) {
161 int rc = doMountVolume(path);
162 if (rc != StorageResultCode.OperationSucceeded) {
163 Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
164 }
165 }
San Mehat6a965af22010-02-24 17:47:30 -0800166 /*
167 * If UMS is connected in boot, send the connected event
168 * now that we're up.
169 */
170 if (mSendUmsConnectedOnBoot) {
171 sendUmsIntent(true);
172 mSendUmsConnectedOnBoot = false;
173 }
San Mehatfafb0412010-02-18 19:40:04 -0800174 } catch (Exception ex) {
175 Log.e(TAG, "Boot-time mount exception", ex);
176 }
San Mehat207e5382010-02-04 20:46:54 -0800177 }
San Mehatfafb0412010-02-18 19:40:04 -0800178 }.start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 }
180 }
181 };
182
San Mehat4270e1e2010-01-29 05:32:19 -0800183 private final class MountServiceBinderListener implements IBinder.DeathRecipient {
184 final IMountServiceListener mListener;
185
186 MountServiceBinderListener(IMountServiceListener listener) {
187 mListener = listener;
188
San Mehat91c77612010-01-07 10:39:41 -0800189 }
190
San Mehat4270e1e2010-01-29 05:32:19 -0800191 public void binderDied() {
San Mehatb1043402010-02-05 08:26:50 -0800192 if (LOCAL_LOGD) Log.d(TAG, "An IMountServiceListener has died!");
San Mehat4270e1e2010-01-29 05:32:19 -0800193 synchronized(mListeners) {
194 mListeners.remove(this);
195 mListener.asBinder().unlinkToDeath(this, 0);
196 }
197 }
198 }
199
San Mehat207e5382010-02-04 20:46:54 -0800200 private int doShareUnshareVolume(String path, String method, boolean enable) {
San Mehat4270e1e2010-01-29 05:32:19 -0800201 validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
202
203 // TODO: Add support for multiple share methods
204 if (!method.equals("ums")) {
205 throw new IllegalArgumentException(String.format("Method %s not supported", method));
206 }
207
208 /*
209 * If the volume is mounted and we're enabling then unmount it
210 */
211 String vs = getVolumeState(path);
212 if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
San Mehatb1043402010-02-05 08:26:50 -0800213 mUmsEnabling = enable; // Override for isUsbMassStorageEnabled()
San Mehat3d488102010-02-22 11:39:16 -0800214 int rc = doUnmountVolume(path, true);
San Mehatb1043402010-02-05 08:26:50 -0800215 mUmsEnabling = false; // Clear override
San Mehat59443a62010-02-09 13:28:45 -0800216 if (rc != StorageResultCode.OperationSucceeded) {
217 Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc));
218 return rc;
219 }
San Mehat4270e1e2010-01-29 05:32:19 -0800220 }
221
222 try {
223 mConnector.doCommand(String.format(
224 "volume %sshare %s %s", (enable ? "" : "un"), path, method));
225 } catch (NativeDaemonConnectorException e) {
226 Log.e(TAG, "Failed to share/unshare", e);
San Mehatb1043402010-02-05 08:26:50 -0800227 return StorageResultCode.OperationFailedInternalError;
San Mehat4270e1e2010-01-29 05:32:19 -0800228 }
229
230 /*
231 * If we disabled UMS then mount the volume
232 */
233 if (!enable) {
San Mehatb1043402010-02-05 08:26:50 -0800234 if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
San Mehat4270e1e2010-01-29 05:32:19 -0800235 Log.e(TAG, String.format(
236 "Failed to remount %s after disabling share method %s", path, method));
237 /*
238 * Even though the mount failed, the unshare didn't so don't indicate an error.
239 * The mountVolume() call will have set the storage state and sent the necessary
240 * broadcasts.
241 */
242 }
243 }
244
San Mehatb1043402010-02-05 08:26:50 -0800245 return StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800246 }
247
San Mehat207e5382010-02-04 20:46:54 -0800248 private void updatePublicVolumeState(String path, String state) {
San Mehat4270e1e2010-01-29 05:32:19 -0800249 if (!path.equals(Environment.getExternalStorageDirectory().getPath())) {
250 Log.w(TAG, "Multiple volumes not currently supported");
251 return;
252 }
San Mehatb1043402010-02-05 08:26:50 -0800253
254 if (mLegacyState.equals(state)) {
255 Log.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state));
256 return;
257 }
San Mehat4270e1e2010-01-29 05:32:19 -0800258
259 String oldState = mLegacyState;
260 mLegacyState = state;
261
262 synchronized (mListeners) {
263 for (int i = mListeners.size() -1; i >= 0; i--) {
264 MountServiceBinderListener bl = mListeners.get(i);
265 try {
San Mehatb1043402010-02-05 08:26:50 -0800266 bl.mListener.onStorageStateChanged(path, oldState, state);
San Mehat4270e1e2010-01-29 05:32:19 -0800267 } catch (RemoteException rex) {
268 Log.e(TAG, "Listener dead");
269 mListeners.remove(i);
270 } catch (Exception ex) {
271 Log.e(TAG, "Listener failed", ex);
272 }
273 }
274 }
275 }
276
277 /**
278 *
279 * Callback from NativeDaemonConnector
280 */
281 public void onDaemonConnected() {
282 /*
283 * Since we'll be calling back into the NativeDaemonConnector,
284 * we need to do our work in a new thread.
285 */
286 new Thread() {
287 public void run() {
288 /**
289 * Determine media state and UMS detection status
290 */
291 String path = Environment.getExternalStorageDirectory().getPath();
292 String state = Environment.MEDIA_REMOVED;
293
294 try {
295 String[] vols = mConnector.doListCommand(
296 "volume list", VoldResponseCode.VolumeListResult);
297 for (String volstr : vols) {
298 String[] tok = volstr.split(" ");
299 // FMT: <label> <mountpoint> <state>
300 if (!tok[1].equals(path)) {
301 Log.w(TAG, String.format(
302 "Skipping unknown volume '%s'",tok[1]));
303 continue;
304 }
305 int st = Integer.parseInt(tok[2]);
306 if (st == VolumeState.NoMedia) {
307 state = Environment.MEDIA_REMOVED;
308 } else if (st == VolumeState.Idle) {
San Mehat207e5382010-02-04 20:46:54 -0800309 state = Environment.MEDIA_UNMOUNTED;
San Mehat4270e1e2010-01-29 05:32:19 -0800310 } else if (st == VolumeState.Mounted) {
311 state = Environment.MEDIA_MOUNTED;
312 Log.i(TAG, "Media already mounted on daemon connection");
313 } else if (st == VolumeState.Shared) {
314 state = Environment.MEDIA_SHARED;
315 Log.i(TAG, "Media shared on daemon connection");
316 } else {
317 throw new Exception(String.format("Unexpected state %d", st));
318 }
319 }
320 if (state != null) {
321 updatePublicVolumeState(path, state);
322 }
323 } catch (Exception e) {
324 Log.e(TAG, "Error processing initial volume state", e);
325 updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
326 }
327
328 try {
San Mehat207e5382010-02-04 20:46:54 -0800329 boolean avail = doGetShareMethodAvailable("ums");
San Mehat4270e1e2010-01-29 05:32:19 -0800330 notifyShareAvailabilityChange("ums", avail);
331 } catch (Exception ex) {
332 Log.w(TAG, "Failed to get share availability");
333 }
San Mehat207e5382010-02-04 20:46:54 -0800334 /*
335 * Now that we've done our initialization, release
336 * the hounds!
337 */
338 mReady = true;
San Mehat4270e1e2010-01-29 05:32:19 -0800339 }
340 }.start();
341 }
342
343 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800344 * Callback from NativeDaemonConnector
345 */
346 public boolean onEvent(int code, String raw, String[] cooked) {
347 Intent in = null;
348
San Mehat4270e1e2010-01-29 05:32:19 -0800349 if (code == VoldResponseCode.VolumeStateChange) {
350 /*
351 * One of the volumes we're managing has changed state.
352 * Format: "NNN Volume <label> <path> state changed
353 * from <old_#> (<old_str>) to <new_#> (<new_str>)"
354 */
355 notifyVolumeStateChange(
356 cooked[2], cooked[3], Integer.parseInt(cooked[7]),
357 Integer.parseInt(cooked[10]));
358 } else if (code == VoldResponseCode.ShareAvailabilityChange) {
359 // FMT: NNN Share method <method> now <available|unavailable>
360 boolean avail = false;
361 if (cooked[5].equals("available")) {
362 avail = true;
363 }
364 notifyShareAvailabilityChange(cooked[3], avail);
365 } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
366 (code == VoldResponseCode.VolumeDiskRemoved) ||
367 (code == VoldResponseCode.VolumeBadRemoval)) {
368 // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
369 // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
370 // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
371 final String label = cooked[2];
372 final String path = cooked[3];
373 int major = -1;
374 int minor = -1;
375
376 try {
377 String devComp = cooked[6].substring(1, cooked[6].length() -1);
378 String[] devTok = devComp.split(":");
379 major = Integer.parseInt(devTok[0]);
380 minor = Integer.parseInt(devTok[1]);
381 } catch (Exception ex) {
382 Log.e(TAG, "Failed to parse major/minor", ex);
383 }
384
San Mehat4270e1e2010-01-29 05:32:19 -0800385 if (code == VoldResponseCode.VolumeDiskInserted) {
386 new Thread() {
387 public void run() {
388 try {
389 int rc;
San Mehatb1043402010-02-05 08:26:50 -0800390 if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
San Mehat4270e1e2010-01-29 05:32:19 -0800391 Log.w(TAG, String.format("Insertion mount failed (%d)", rc));
392 }
393 } catch (Exception ex) {
394 Log.w(TAG, "Failed to mount media on insertion", ex);
395 }
396 }
397 }.start();
398 } else if (code == VoldResponseCode.VolumeDiskRemoved) {
399 /*
400 * This event gets trumped if we're already in BAD_REMOVAL state
401 */
402 if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
403 return true;
404 }
405 /* Send the media unmounted event first */
406 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
407 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
408 mContext.sendBroadcast(in);
409
410 updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
411 in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path));
412 } else if (code == VoldResponseCode.VolumeBadRemoval) {
413 /* Send the media unmounted event first */
414 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
415 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
416 mContext.sendBroadcast(in);
417
418 updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
419 in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path));
420 } else {
421 Log.e(TAG, String.format("Unknown code {%d}", code));
422 }
423 } else {
424 return false;
425 }
426
427 if (in != null) {
428 mContext.sendBroadcast(in);
429 }
430 return true;
431 }
432
San Mehat207e5382010-02-04 20:46:54 -0800433 private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
San Mehat4270e1e2010-01-29 05:32:19 -0800434 String vs = getVolumeState(path);
435
436 Intent in = null;
437
438 if (newState == VolumeState.Init) {
439 } else if (newState == VolumeState.NoMedia) {
440 // NoMedia is handled via Disk Remove events
441 } else if (newState == VolumeState.Idle) {
442 /*
443 * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
444 * if we're in the process of enabling UMS
445 */
446 if (!vs.equals(
447 Environment.MEDIA_BAD_REMOVAL) && !vs.equals(
448 Environment.MEDIA_NOFS) && !vs.equals(
449 Environment.MEDIA_UNMOUNTABLE) && !mUmsEnabling) {
450 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
451 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
452 }
453 } else if (newState == VolumeState.Pending) {
454 } else if (newState == VolumeState.Checking) {
455 updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
456 in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path));
457 } else if (newState == VolumeState.Mounted) {
458 updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
459 // Update media status on PackageManagerService to mount packages on sdcard
460 mPms.updateExternalMediaStatus(true);
461 in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path));
462 in.putExtra("read-only", false);
463 } else if (newState == VolumeState.Unmounting) {
464 mPms.updateExternalMediaStatus(false);
465 in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path));
466 } else if (newState == VolumeState.Formatting) {
467 } else if (newState == VolumeState.Shared) {
468 /* Send the media unmounted event first */
469 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
470 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
471 mContext.sendBroadcast(in);
472
473 updatePublicVolumeState(path, Environment.MEDIA_SHARED);
474 in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path));
475 } else if (newState == VolumeState.SharedMnt) {
476 Log.e(TAG, "Live shared mounts not supported yet!");
477 return;
478 } else {
479 Log.e(TAG, "Unhandled VolumeState {" + newState + "}");
480 }
481
482 if (in != null) {
483 mContext.sendBroadcast(in);
484 }
485 }
486
San Mehat207e5382010-02-04 20:46:54 -0800487 private boolean doGetShareMethodAvailable(String method) {
488 ArrayList<String> rsp = mConnector.doCommand("share status " + method);
489
490 for (String line : rsp) {
491 String []tok = line.split(" ");
492 int code;
493 try {
494 code = Integer.parseInt(tok[0]);
495 } catch (NumberFormatException nfe) {
496 Log.e(TAG, String.format("Error parsing code %s", tok[0]));
497 return false;
498 }
499 if (code == VoldResponseCode.ShareStatusResult) {
500 if (tok[2].equals("available"))
501 return true;
502 return false;
503 } else {
504 Log.e(TAG, String.format("Unexpected response code %d", code));
505 return false;
506 }
507 }
508 Log.e(TAG, "Got an empty response");
509 return false;
510 }
511
512 private int doMountVolume(String path) {
San Mehatb1043402010-02-05 08:26:50 -0800513 int rc = StorageResultCode.OperationSucceeded;
San Mehat207e5382010-02-04 20:46:54 -0800514
515 try {
516 mConnector.doCommand(String.format("volume mount %s", path));
517 } catch (NativeDaemonConnectorException e) {
518 /*
519 * Mount failed for some reason
520 */
521 Intent in = null;
522 int code = e.getCode();
523 if (code == VoldResponseCode.OpFailedNoMedia) {
524 /*
525 * Attempt to mount but no media inserted
526 */
San Mehatb1043402010-02-05 08:26:50 -0800527 rc = StorageResultCode.OperationFailedNoMedia;
San Mehat207e5382010-02-04 20:46:54 -0800528 } else if (code == VoldResponseCode.OpFailedMediaBlank) {
529 /*
530 * Media is blank or does not contain a supported filesystem
531 */
532 updatePublicVolumeState(path, Environment.MEDIA_NOFS);
533 in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path));
San Mehatb1043402010-02-05 08:26:50 -0800534 rc = StorageResultCode.OperationFailedMediaBlank;
San Mehat207e5382010-02-04 20:46:54 -0800535 } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
536 /*
537 * Volume consistency check failed
538 */
539 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
540 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path));
San Mehatb1043402010-02-05 08:26:50 -0800541 rc = StorageResultCode.OperationFailedMediaCorrupt;
San Mehat207e5382010-02-04 20:46:54 -0800542 } else {
San Mehatb1043402010-02-05 08:26:50 -0800543 rc = StorageResultCode.OperationFailedInternalError;
San Mehat207e5382010-02-04 20:46:54 -0800544 }
545
546 /*
547 * Send broadcast intent (if required for the failure)
548 */
549 if (in != null) {
550 mContext.sendBroadcast(in);
551 }
552 }
553
554 return rc;
555 }
556
San Mehatd9709982010-02-18 11:43:03 -0800557 private int doUnmountVolume(String path, boolean force) {
San Mehat59443a62010-02-09 13:28:45 -0800558 if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
San Mehat207e5382010-02-04 20:46:54 -0800559 return VoldResponseCode.OpFailedVolNotMounted;
560 }
561
562 // Notify PackageManager of potential media removal and deal with
563 // return code later on. The caller of this api should be aware or have been
564 // notified that the applications installed on the media will be killed.
565 mPms.updateExternalMediaStatus(false);
566 try {
San Mehatd9709982010-02-18 11:43:03 -0800567 mConnector.doCommand(String.format(
568 "volume unmount %s%s", path, (force ? " force" : "")));
San Mehatb1043402010-02-05 08:26:50 -0800569 return StorageResultCode.OperationSucceeded;
San Mehat207e5382010-02-04 20:46:54 -0800570 } catch (NativeDaemonConnectorException e) {
571 // Don't worry about mismatch in PackageManager since the
572 // call back will handle the status changes any way.
573 int code = e.getCode();
574 if (code == VoldResponseCode.OpFailedVolNotMounted) {
San Mehata181b212010-02-11 06:50:20 -0800575 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehatd9709982010-02-18 11:43:03 -0800576 } else if (code == VoldResponseCode.OpFailedStorageBusy) {
577 return StorageResultCode.OperationFailedStorageBusy;
San Mehat207e5382010-02-04 20:46:54 -0800578 } else {
San Mehatb1043402010-02-05 08:26:50 -0800579 return StorageResultCode.OperationFailedInternalError;
San Mehat207e5382010-02-04 20:46:54 -0800580 }
581 }
582 }
583
584 private int doFormatVolume(String path) {
585 try {
586 String cmd = String.format("volume format %s", path);
587 mConnector.doCommand(cmd);
San Mehatb1043402010-02-05 08:26:50 -0800588 return StorageResultCode.OperationSucceeded;
San Mehat207e5382010-02-04 20:46:54 -0800589 } catch (NativeDaemonConnectorException e) {
590 int code = e.getCode();
591 if (code == VoldResponseCode.OpFailedNoMedia) {
San Mehatb1043402010-02-05 08:26:50 -0800592 return StorageResultCode.OperationFailedNoMedia;
San Mehat207e5382010-02-04 20:46:54 -0800593 } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
San Mehatb1043402010-02-05 08:26:50 -0800594 return StorageResultCode.OperationFailedMediaCorrupt;
San Mehat207e5382010-02-04 20:46:54 -0800595 } else {
San Mehatb1043402010-02-05 08:26:50 -0800596 return StorageResultCode.OperationFailedInternalError;
San Mehat207e5382010-02-04 20:46:54 -0800597 }
598 }
599 }
600
San Mehatb1043402010-02-05 08:26:50 -0800601 private boolean doGetVolumeShared(String path, String method) {
602 String cmd = String.format("volume shared %s %s", path, method);
603 ArrayList<String> rsp = mConnector.doCommand(cmd);
604
605 for (String line : rsp) {
606 String []tok = line.split(" ");
607 int code;
608 try {
609 code = Integer.parseInt(tok[0]);
610 } catch (NumberFormatException nfe) {
611 Log.e(TAG, String.format("Error parsing code %s", tok[0]));
612 return false;
613 }
614 if (code == VoldResponseCode.ShareEnabledResult) {
615 if (tok[2].equals("enabled"))
616 return true;
617 return false;
618 } else {
619 Log.e(TAG, String.format("Unexpected response code %d", code));
620 return false;
621 }
622 }
623 Log.e(TAG, "Got an empty response");
624 return false;
625 }
626
San Mehat207e5382010-02-04 20:46:54 -0800627 private void notifyShareAvailabilityChange(String method, final boolean avail) {
San Mehat4270e1e2010-01-29 05:32:19 -0800628 if (!method.equals("ums")) {
629 Log.w(TAG, "Ignoring unsupported share method {" + method + "}");
630 return;
631 }
632
633 synchronized (mListeners) {
634 for (int i = mListeners.size() -1; i >= 0; i--) {
635 MountServiceBinderListener bl = mListeners.get(i);
636 try {
San Mehatb1043402010-02-05 08:26:50 -0800637 bl.mListener.onUsbMassStorageConnectionChanged(avail);
San Mehat4270e1e2010-01-29 05:32:19 -0800638 } catch (RemoteException rex) {
639 Log.e(TAG, "Listener dead");
640 mListeners.remove(i);
641 } catch (Exception ex) {
642 Log.e(TAG, "Listener failed", ex);
643 }
644 }
645 }
646
San Mehat207e5382010-02-04 20:46:54 -0800647 if (mBooted == true) {
San Mehat6a965af22010-02-24 17:47:30 -0800648 sendUmsIntent(avail);
649 } else {
650 mSendUmsConnectedOnBoot = avail;
San Mehat4270e1e2010-01-29 05:32:19 -0800651 }
San Mehat4270e1e2010-01-29 05:32:19 -0800652 }
653
San Mehat6a965af22010-02-24 17:47:30 -0800654 private void sendUmsIntent(boolean c) {
655 mContext.sendBroadcast(
656 new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)));
657 }
658
San Mehat207e5382010-02-04 20:46:54 -0800659 private void validatePermission(String perm) {
San Mehat4270e1e2010-01-29 05:32:19 -0800660 if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
661 throw new SecurityException(String.format("Requires %s permission", perm));
662 }
663 }
664
665 /**
San Mehat207e5382010-02-04 20:46:54 -0800666 * Constructs a new MountService instance
667 *
668 * @param context Binder context for this service
669 */
670 public MountService(Context context) {
671 mContext = context;
672
San Mehat207e5382010-02-04 20:46:54 -0800673 // XXX: This will go away soon in favor of IMountServiceObserver
674 mPms = (PackageManagerService) ServiceManager.getService("package");
675
676 mContext.registerReceiver(mBroadcastReceiver,
677 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
678
679 mListeners = new ArrayList<MountServiceBinderListener>();
680
Marco Nelissenc34ebce2010-02-18 13:39:41 -0800681 /*
682 * Vold does not run in the simulator, so pretend the connector thread
683 * ran and did its thing.
684 */
685 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
686 mReady = true;
687 mUmsEnabling = true;
688 return;
689 }
690
San Mehat207e5382010-02-04 20:46:54 -0800691 mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
692 mReady = false;
693 Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
694 thread.start();
695 }
696
697 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800698 * Exposed API calls below here
699 */
700
701 public void registerListener(IMountServiceListener listener) {
702 synchronized (mListeners) {
703 MountServiceBinderListener bl = new MountServiceBinderListener(listener);
704 try {
705 listener.asBinder().linkToDeath(bl, 0);
706 mListeners.add(bl);
707 } catch (RemoteException rex) {
708 Log.e(TAG, "Failed to link to listener death");
709 }
710 }
711 }
712
713 public void unregisterListener(IMountServiceListener listener) {
714 synchronized (mListeners) {
715 for(MountServiceBinderListener bl : mListeners) {
716 if (bl.mListener == listener) {
717 mListeners.remove(mListeners.indexOf(bl));
718 return;
719 }
720 }
721 }
722 }
723
724 public void shutdown() {
725 validatePermission(android.Manifest.permission.SHUTDOWN);
726
727 Log.i(TAG, "Shutting down");
728
729 String path = Environment.getExternalStorageDirectory().getPath();
730 String state = getVolumeState(path);
San Mehat91c77612010-01-07 10:39:41 -0800731
732 if (state.equals(Environment.MEDIA_SHARED)) {
733 /*
734 * If the media is currently shared, unshare it.
735 * XXX: This is still dangerous!. We should not
736 * be rebooting at *all* if UMS is enabled, since
737 * the UMS host could have dirty FAT cache entries
738 * yet to flush.
739 */
San Mehatb1043402010-02-05 08:26:50 -0800740 if (setUsbMassStorageEnabled(false) != StorageResultCode.OperationSucceeded) {
San Mehat4270e1e2010-01-29 05:32:19 -0800741 Log.e(TAG, "UMS disable on shutdown failed");
San Mehat91c77612010-01-07 10:39:41 -0800742 }
743 } else if (state.equals(Environment.MEDIA_CHECKING)) {
744 /*
745 * If the media is being checked, then we need to wait for
746 * it to complete before being able to proceed.
747 */
748 // XXX: @hackbod - Should we disable the ANR timer here?
749 int retries = 30;
750 while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
751 try {
752 Thread.sleep(1000);
753 } catch (InterruptedException iex) {
754 Log.e(TAG, "Interrupted while waiting for media", iex);
755 break;
756 }
757 state = Environment.getExternalStorageState();
758 }
759 if (retries == 0) {
760 Log.e(TAG, "Timed out waiting for media to check");
761 }
762 }
763
764 if (state.equals(Environment.MEDIA_MOUNTED)) {
765 /*
766 * If the media is mounted, then gracefully unmount it.
767 */
San Mehatd9709982010-02-18 11:43:03 -0800768 if (doUnmountVolume(path, true) != StorageResultCode.OperationSucceeded) {
San Mehat4270e1e2010-01-29 05:32:19 -0800769 Log.e(TAG, "Failed to unmount media for shutdown");
770 }
771 }
772 }
773
San Mehatb1043402010-02-05 08:26:50 -0800774 public boolean isUsbMassStorageConnected() {
San Mehat207e5382010-02-04 20:46:54 -0800775 waitForReady();
San Mehat91c77612010-01-07 10:39:41 -0800776
San Mehatb1043402010-02-05 08:26:50 -0800777 if (mUmsEnabling) {
778 return true;
San Mehat7fd0fee2009-12-17 07:12:23 -0800779 }
San Mehatb1043402010-02-05 08:26:50 -0800780 return doGetShareMethodAvailable("ums");
781 }
782
783 public int setUsbMassStorageEnabled(boolean enable) {
784 waitForReady();
785
786 return doShareUnshareVolume(Environment.getExternalStorageDirectory().getPath(), "ums", enable);
787 }
788
789 public boolean isUsbMassStorageEnabled() {
790 waitForReady();
791 return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 }
San Mehat4270e1e2010-01-29 05:32:19 -0800793
San Mehat7fd0fee2009-12-17 07:12:23 -0800794 /**
795 * @return state of the volume at the specified mount point
796 */
San Mehat4270e1e2010-01-29 05:32:19 -0800797 public String getVolumeState(String mountPoint) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800798 /*
799 * XXX: Until we have multiple volume discovery, just hardwire
800 * this to /sdcard
801 */
802 if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
803 Log.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
804 throw new IllegalArgumentException();
805 }
806
807 return mLegacyState;
808 }
809
San Mehat4270e1e2010-01-29 05:32:19 -0800810 public int mountVolume(String path) {
811 validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehat4270e1e2010-01-29 05:32:19 -0800812
San Mehat207e5382010-02-04 20:46:54 -0800813 waitForReady();
814 return doMountVolume(path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 }
816
San Mehatd9709982010-02-18 11:43:03 -0800817 public int unmountVolume(String path, boolean force) {
San Mehat4270e1e2010-01-29 05:32:19 -0800818 validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -0800819 waitForReady();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820
San Mehatd9709982010-02-18 11:43:03 -0800821 return doUnmountVolume(path, force);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 }
823
San Mehat4270e1e2010-01-29 05:32:19 -0800824 public int formatVolume(String path) {
825 validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -0800826 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -0800827
San Mehat207e5382010-02-04 20:46:54 -0800828 return doFormatVolume(path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 }
830
San Mehatc1b4ce92010-02-16 17:13:03 -0800831 public int []getStorageUsers(String path) {
832 validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
833 waitForReady();
834 try {
835 String[] r = mConnector.doListCommand(
836 String.format("storage users %s", path),
837 VoldResponseCode.StorageUsersListResult);
838 // FMT: <pid> <process name>
839 int[] data = new int[r.length];
840 for (int i = 0; i < r.length; i++) {
841 String []tok = r[i].split(" ");
842 try {
843 data[i] = Integer.parseInt(tok[0]);
844 } catch (NumberFormatException nfe) {
845 Log.e(TAG, String.format("Error parsing pid %s", tok[0]));
846 return new int[0];
847 }
848 }
849 return data;
850 } catch (NativeDaemonConnectorException e) {
851 Log.e(TAG, "Failed to retrieve storage users list", e);
852 return new int[0];
853 }
854 }
855
San Mehatb1043402010-02-05 08:26:50 -0800856 private void warnOnNotMounted() {
857 if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
858 Log.w(TAG, "getSecureContainerList() called when storage not mounted");
859 }
860 }
861
San Mehat4270e1e2010-01-29 05:32:19 -0800862 public String[] getSecureContainerList() {
863 validatePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -0800864 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800865 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -0800866
San Mehat4270e1e2010-01-29 05:32:19 -0800867 try {
868 return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult);
869 } catch (NativeDaemonConnectorException e) {
870 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 }
872 }
San Mehat36972292010-01-06 11:06:32 -0800873
San Mehat4270e1e2010-01-29 05:32:19 -0800874 public int createSecureContainer(String id, int sizeMb, String fstype,
875 String key, int ownerUid) {
876 validatePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -0800877 waitForReady();
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 String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid);
882 try {
883 mConnector.doCommand(cmd);
884 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -0800885 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -0800886 }
San Mehata181b212010-02-11 06:50:20 -0800887
888 if (rc == StorageResultCode.OperationSucceeded) {
889 synchronized (mAsecMountSet) {
890 mAsecMountSet.add(id);
891 }
892 }
San Mehat4270e1e2010-01-29 05:32:19 -0800893 return rc;
San Mehat36972292010-01-06 11:06:32 -0800894 }
895
San Mehat4270e1e2010-01-29 05:32:19 -0800896 public int finalizeSecureContainer(String id) {
897 validatePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -0800898 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800899
San Mehatb1043402010-02-05 08:26:50 -0800900 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800901 try {
902 mConnector.doCommand(String.format("asec finalize %s", id));
San Mehata181b212010-02-11 06:50:20 -0800903 /*
904 * Finalization does a remount, so no need
905 * to update mAsecMountSet
906 */
San Mehat4270e1e2010-01-29 05:32:19 -0800907 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -0800908 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -0800909 }
San Mehat4270e1e2010-01-29 05:32:19 -0800910 return rc;
San Mehat36972292010-01-06 11:06:32 -0800911 }
912
San Mehatd9709982010-02-18 11:43:03 -0800913 public int destroySecureContainer(String id, boolean force) {
San Mehat4270e1e2010-01-29 05:32:19 -0800914 validatePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -0800915 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800916 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -0800917
San Mehatb1043402010-02-05 08:26:50 -0800918 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800919 try {
San Mehatd9709982010-02-18 11:43:03 -0800920 mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
San Mehat4270e1e2010-01-29 05:32:19 -0800921 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -0800922 int code = e.getCode();
923 if (code == VoldResponseCode.OpFailedStorageBusy) {
924 rc = StorageResultCode.OperationFailedStorageBusy;
925 } else {
926 rc = StorageResultCode.OperationFailedInternalError;
927 }
San Mehat02735bc2010-01-26 15:18:08 -0800928 }
San Mehata181b212010-02-11 06:50:20 -0800929
930 if (rc == StorageResultCode.OperationSucceeded) {
931 synchronized (mAsecMountSet) {
932 if (mAsecMountSet.contains(id)) {
933 mAsecMountSet.remove(id);
934 }
935 }
936 }
937
San Mehat4270e1e2010-01-29 05:32:19 -0800938 return rc;
San Mehat36972292010-01-06 11:06:32 -0800939 }
940
San Mehat4270e1e2010-01-29 05:32:19 -0800941 public int mountSecureContainer(String id, String key, int ownerUid) {
942 validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -0800943 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800944 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800945
San Mehata181b212010-02-11 06:50:20 -0800946 synchronized (mAsecMountSet) {
947 if (mAsecMountSet.contains(id)) {
948 return StorageResultCode.OperationFailedStorageMounted;
949 }
950 }
951
San Mehatb1043402010-02-05 08:26:50 -0800952 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800953 String cmd = String.format("asec mount %s %s %d", id, key, ownerUid);
954 try {
955 mConnector.doCommand(cmd);
956 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -0800957 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -0800958 }
San Mehat6cdd9c02010-02-09 14:45:20 -0800959
960 if (rc == StorageResultCode.OperationSucceeded) {
961 synchronized (mAsecMountSet) {
962 mAsecMountSet.add(id);
963 }
964 }
San Mehat4270e1e2010-01-29 05:32:19 -0800965 return rc;
San Mehat36972292010-01-06 11:06:32 -0800966 }
967
San Mehatd9709982010-02-18 11:43:03 -0800968 public int unmountSecureContainer(String id, boolean force) {
San Mehat4270e1e2010-01-29 05:32:19 -0800969 validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -0800970 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800971 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800972
San Mehat6cdd9c02010-02-09 14:45:20 -0800973 synchronized (mAsecMountSet) {
974 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -0800975 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -0800976 }
977 }
978
San Mehatb1043402010-02-05 08:26:50 -0800979 int rc = StorageResultCode.OperationSucceeded;
San Mehatd9709982010-02-18 11:43:03 -0800980 String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
San Mehat4270e1e2010-01-29 05:32:19 -0800981 try {
982 mConnector.doCommand(cmd);
983 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -0800984 int code = e.getCode();
985 if (code == VoldResponseCode.OpFailedStorageBusy) {
986 rc = StorageResultCode.OperationFailedStorageBusy;
987 } else {
988 rc = StorageResultCode.OperationFailedInternalError;
989 }
San Mehat02735bc2010-01-26 15:18:08 -0800990 }
San Mehat6cdd9c02010-02-09 14:45:20 -0800991
992 if (rc == StorageResultCode.OperationSucceeded) {
993 synchronized (mAsecMountSet) {
994 mAsecMountSet.remove(id);
995 }
996 }
San Mehat4270e1e2010-01-29 05:32:19 -0800997 return rc;
San Mehat9dba7092010-01-18 06:47:41 -0800998 }
999
San Mehat6cdd9c02010-02-09 14:45:20 -08001000 public boolean isSecureContainerMounted(String id) {
1001 validatePermission(android.Manifest.permission.ASEC_ACCESS);
1002 waitForReady();
1003 warnOnNotMounted();
1004
1005 synchronized (mAsecMountSet) {
1006 return mAsecMountSet.contains(id);
1007 }
1008 }
1009
San Mehat4270e1e2010-01-29 05:32:19 -08001010 public int renameSecureContainer(String oldId, String newId) {
1011 validatePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08001012 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001013 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08001014
San Mehata181b212010-02-11 06:50:20 -08001015 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08001016 /*
1017 * Because a mounted container has active internal state which cannot be
1018 * changed while active, we must ensure both ids are not currently mounted.
1019 */
1020 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08001021 return StorageResultCode.OperationFailedStorageMounted;
1022 }
1023 }
1024
San Mehatb1043402010-02-05 08:26:50 -08001025 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08001026 String cmd = String.format("asec rename %s %s", oldId, newId);
1027 try {
1028 mConnector.doCommand(cmd);
1029 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08001030 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08001031 }
San Mehata181b212010-02-11 06:50:20 -08001032
San Mehat4270e1e2010-01-29 05:32:19 -08001033 return rc;
San Mehat45f61042010-01-23 08:12:43 -08001034 }
1035
San Mehat4270e1e2010-01-29 05:32:19 -08001036 public String getSecureContainerPath(String id) {
1037 validatePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08001038 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001039 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08001040
San Mehat4270e1e2010-01-29 05:32:19 -08001041 ArrayList<String> rsp = mConnector.doCommand("asec path " + id);
San Mehat36972292010-01-06 11:06:32 -08001042
San Mehat22dd86e2010-01-12 12:21:18 -08001043 for (String line : rsp) {
1044 String []tok = line.split(" ");
1045 int code = Integer.parseInt(tok[0]);
1046 if (code == VoldResponseCode.AsecPathResult) {
1047 return tok[1];
1048 } else {
San Mehat4270e1e2010-01-29 05:32:19 -08001049 Log.e(TAG, String.format("Unexpected response code %d", code));
1050 return "";
San Mehat22dd86e2010-01-12 12:21:18 -08001051 }
1052 }
San Mehat4270e1e2010-01-29 05:32:19 -08001053
1054 Log.e(TAG, "Got an empty response");
1055 return "";
San Mehat22dd86e2010-01-12 12:21:18 -08001056 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057}
1058