blob: ad377e35296b5d2bd3bbf6036f79bf139575d9b7 [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
San Mehat207e5382010-02-04 20:46:54 -0800145 String path = Environment.getExternalStorageDirectory().getPath();
146 if (getVolumeState(path).equals(Environment.MEDIA_UNMOUNTED)) {
147 int rc = doMountVolume(path);
San Mehatb1043402010-02-05 08:26:50 -0800148 if (rc != StorageResultCode.OperationSucceeded) {
San Mehat207e5382010-02-04 20:46:54 -0800149 Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
150 }
151 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 }
153 }
154 };
155
San Mehat4270e1e2010-01-29 05:32:19 -0800156 private final class MountServiceBinderListener implements IBinder.DeathRecipient {
157 final IMountServiceListener mListener;
158
159 MountServiceBinderListener(IMountServiceListener listener) {
160 mListener = listener;
161
San Mehat91c77612010-01-07 10:39:41 -0800162 }
163
San Mehat4270e1e2010-01-29 05:32:19 -0800164 public void binderDied() {
San Mehatb1043402010-02-05 08:26:50 -0800165 if (LOCAL_LOGD) Log.d(TAG, "An IMountServiceListener has died!");
San Mehat4270e1e2010-01-29 05:32:19 -0800166 synchronized(mListeners) {
167 mListeners.remove(this);
168 mListener.asBinder().unlinkToDeath(this, 0);
169 }
170 }
171 }
172
San Mehat207e5382010-02-04 20:46:54 -0800173 private int doShareUnshareVolume(String path, String method, boolean enable) {
San Mehat4270e1e2010-01-29 05:32:19 -0800174 validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
175
176 // TODO: Add support for multiple share methods
177 if (!method.equals("ums")) {
178 throw new IllegalArgumentException(String.format("Method %s not supported", method));
179 }
180
181 /*
182 * If the volume is mounted and we're enabling then unmount it
183 */
184 String vs = getVolumeState(path);
185 if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
San Mehatb1043402010-02-05 08:26:50 -0800186 mUmsEnabling = enable; // Override for isUsbMassStorageEnabled()
San Mehatd9709982010-02-18 11:43:03 -0800187 int rc = doUnmountVolume(path, false);
San Mehatb1043402010-02-05 08:26:50 -0800188 mUmsEnabling = false; // Clear override
San Mehat59443a62010-02-09 13:28:45 -0800189 if (rc != StorageResultCode.OperationSucceeded) {
190 Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc));
191 return rc;
192 }
San Mehat4270e1e2010-01-29 05:32:19 -0800193 }
194
195 try {
196 mConnector.doCommand(String.format(
197 "volume %sshare %s %s", (enable ? "" : "un"), path, method));
198 } catch (NativeDaemonConnectorException e) {
199 Log.e(TAG, "Failed to share/unshare", e);
San Mehatb1043402010-02-05 08:26:50 -0800200 return StorageResultCode.OperationFailedInternalError;
San Mehat4270e1e2010-01-29 05:32:19 -0800201 }
202
203 /*
204 * If we disabled UMS then mount the volume
205 */
206 if (!enable) {
San Mehatb1043402010-02-05 08:26:50 -0800207 if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
San Mehat4270e1e2010-01-29 05:32:19 -0800208 Log.e(TAG, String.format(
209 "Failed to remount %s after disabling share method %s", path, method));
210 /*
211 * Even though the mount failed, the unshare didn't so don't indicate an error.
212 * The mountVolume() call will have set the storage state and sent the necessary
213 * broadcasts.
214 */
215 }
216 }
217
San Mehatb1043402010-02-05 08:26:50 -0800218 return StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800219 }
220
San Mehat207e5382010-02-04 20:46:54 -0800221 private void updatePublicVolumeState(String path, String state) {
San Mehat4270e1e2010-01-29 05:32:19 -0800222 if (!path.equals(Environment.getExternalStorageDirectory().getPath())) {
223 Log.w(TAG, "Multiple volumes not currently supported");
224 return;
225 }
San Mehatb1043402010-02-05 08:26:50 -0800226
227 if (mLegacyState.equals(state)) {
228 Log.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state));
229 return;
230 }
San Mehat4270e1e2010-01-29 05:32:19 -0800231
232 String oldState = mLegacyState;
233 mLegacyState = state;
234
235 synchronized (mListeners) {
236 for (int i = mListeners.size() -1; i >= 0; i--) {
237 MountServiceBinderListener bl = mListeners.get(i);
238 try {
San Mehatb1043402010-02-05 08:26:50 -0800239 bl.mListener.onStorageStateChanged(path, oldState, state);
San Mehat4270e1e2010-01-29 05:32:19 -0800240 } catch (RemoteException rex) {
241 Log.e(TAG, "Listener dead");
242 mListeners.remove(i);
243 } catch (Exception ex) {
244 Log.e(TAG, "Listener failed", ex);
245 }
246 }
247 }
248 }
249
250 /**
251 *
252 * Callback from NativeDaemonConnector
253 */
254 public void onDaemonConnected() {
255 /*
256 * Since we'll be calling back into the NativeDaemonConnector,
257 * we need to do our work in a new thread.
258 */
259 new Thread() {
260 public void run() {
261 /**
262 * Determine media state and UMS detection status
263 */
264 String path = Environment.getExternalStorageDirectory().getPath();
265 String state = Environment.MEDIA_REMOVED;
266
267 try {
268 String[] vols = mConnector.doListCommand(
269 "volume list", VoldResponseCode.VolumeListResult);
270 for (String volstr : vols) {
271 String[] tok = volstr.split(" ");
272 // FMT: <label> <mountpoint> <state>
273 if (!tok[1].equals(path)) {
274 Log.w(TAG, String.format(
275 "Skipping unknown volume '%s'",tok[1]));
276 continue;
277 }
278 int st = Integer.parseInt(tok[2]);
279 if (st == VolumeState.NoMedia) {
280 state = Environment.MEDIA_REMOVED;
281 } else if (st == VolumeState.Idle) {
San Mehat207e5382010-02-04 20:46:54 -0800282 state = Environment.MEDIA_UNMOUNTED;
San Mehat4270e1e2010-01-29 05:32:19 -0800283 } else if (st == VolumeState.Mounted) {
284 state = Environment.MEDIA_MOUNTED;
285 Log.i(TAG, "Media already mounted on daemon connection");
286 } else if (st == VolumeState.Shared) {
287 state = Environment.MEDIA_SHARED;
288 Log.i(TAG, "Media shared on daemon connection");
289 } else {
290 throw new Exception(String.format("Unexpected state %d", st));
291 }
292 }
293 if (state != null) {
294 updatePublicVolumeState(path, state);
295 }
296 } catch (Exception e) {
297 Log.e(TAG, "Error processing initial volume state", e);
298 updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
299 }
300
301 try {
San Mehat207e5382010-02-04 20:46:54 -0800302 boolean avail = doGetShareMethodAvailable("ums");
San Mehat4270e1e2010-01-29 05:32:19 -0800303 notifyShareAvailabilityChange("ums", avail);
304 } catch (Exception ex) {
305 Log.w(TAG, "Failed to get share availability");
306 }
San Mehat207e5382010-02-04 20:46:54 -0800307 /*
308 * Now that we've done our initialization, release
309 * the hounds!
310 */
311 mReady = true;
San Mehat4270e1e2010-01-29 05:32:19 -0800312 }
313 }.start();
314 }
315
316 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800317 * Callback from NativeDaemonConnector
318 */
319 public boolean onEvent(int code, String raw, String[] cooked) {
320 Intent in = null;
321
San Mehat4270e1e2010-01-29 05:32:19 -0800322 if (code == VoldResponseCode.VolumeStateChange) {
323 /*
324 * One of the volumes we're managing has changed state.
325 * Format: "NNN Volume <label> <path> state changed
326 * from <old_#> (<old_str>) to <new_#> (<new_str>)"
327 */
328 notifyVolumeStateChange(
329 cooked[2], cooked[3], Integer.parseInt(cooked[7]),
330 Integer.parseInt(cooked[10]));
331 } else if (code == VoldResponseCode.ShareAvailabilityChange) {
332 // FMT: NNN Share method <method> now <available|unavailable>
333 boolean avail = false;
334 if (cooked[5].equals("available")) {
335 avail = true;
336 }
337 notifyShareAvailabilityChange(cooked[3], avail);
338 } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
339 (code == VoldResponseCode.VolumeDiskRemoved) ||
340 (code == VoldResponseCode.VolumeBadRemoval)) {
341 // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
342 // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
343 // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
344 final String label = cooked[2];
345 final String path = cooked[3];
346 int major = -1;
347 int minor = -1;
348
349 try {
350 String devComp = cooked[6].substring(1, cooked[6].length() -1);
351 String[] devTok = devComp.split(":");
352 major = Integer.parseInt(devTok[0]);
353 minor = Integer.parseInt(devTok[1]);
354 } catch (Exception ex) {
355 Log.e(TAG, "Failed to parse major/minor", ex);
356 }
357
San Mehat4270e1e2010-01-29 05:32:19 -0800358 if (code == VoldResponseCode.VolumeDiskInserted) {
359 new Thread() {
360 public void run() {
361 try {
362 int rc;
San Mehatb1043402010-02-05 08:26:50 -0800363 if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
San Mehat4270e1e2010-01-29 05:32:19 -0800364 Log.w(TAG, String.format("Insertion mount failed (%d)", rc));
365 }
366 } catch (Exception ex) {
367 Log.w(TAG, "Failed to mount media on insertion", ex);
368 }
369 }
370 }.start();
371 } else if (code == VoldResponseCode.VolumeDiskRemoved) {
372 /*
373 * This event gets trumped if we're already in BAD_REMOVAL state
374 */
375 if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
376 return true;
377 }
378 /* Send the media unmounted event first */
379 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
380 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
381 mContext.sendBroadcast(in);
382
383 updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
384 in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path));
385 } else if (code == VoldResponseCode.VolumeBadRemoval) {
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_BAD_REMOVAL);
392 in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path));
393 } else {
394 Log.e(TAG, String.format("Unknown code {%d}", code));
395 }
396 } else {
397 return false;
398 }
399
400 if (in != null) {
401 mContext.sendBroadcast(in);
402 }
403 return true;
404 }
405
San Mehat207e5382010-02-04 20:46:54 -0800406 private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
San Mehat4270e1e2010-01-29 05:32:19 -0800407 String vs = getVolumeState(path);
408
409 Intent in = null;
410
411 if (newState == VolumeState.Init) {
412 } else if (newState == VolumeState.NoMedia) {
413 // NoMedia is handled via Disk Remove events
414 } else if (newState == VolumeState.Idle) {
415 /*
416 * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
417 * if we're in the process of enabling UMS
418 */
419 if (!vs.equals(
420 Environment.MEDIA_BAD_REMOVAL) && !vs.equals(
421 Environment.MEDIA_NOFS) && !vs.equals(
422 Environment.MEDIA_UNMOUNTABLE) && !mUmsEnabling) {
423 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
424 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
425 }
426 } else if (newState == VolumeState.Pending) {
427 } else if (newState == VolumeState.Checking) {
428 updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
429 in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path));
430 } else if (newState == VolumeState.Mounted) {
431 updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
432 // Update media status on PackageManagerService to mount packages on sdcard
433 mPms.updateExternalMediaStatus(true);
434 in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path));
435 in.putExtra("read-only", false);
436 } else if (newState == VolumeState.Unmounting) {
437 mPms.updateExternalMediaStatus(false);
438 in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path));
439 } else if (newState == VolumeState.Formatting) {
440 } else if (newState == VolumeState.Shared) {
441 /* Send the media unmounted event first */
442 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
443 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
444 mContext.sendBroadcast(in);
445
446 updatePublicVolumeState(path, Environment.MEDIA_SHARED);
447 in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path));
448 } else if (newState == VolumeState.SharedMnt) {
449 Log.e(TAG, "Live shared mounts not supported yet!");
450 return;
451 } else {
452 Log.e(TAG, "Unhandled VolumeState {" + newState + "}");
453 }
454
455 if (in != null) {
456 mContext.sendBroadcast(in);
457 }
458 }
459
San Mehat207e5382010-02-04 20:46:54 -0800460 private boolean doGetShareMethodAvailable(String method) {
461 ArrayList<String> rsp = mConnector.doCommand("share status " + method);
462
463 for (String line : rsp) {
464 String []tok = line.split(" ");
465 int code;
466 try {
467 code = Integer.parseInt(tok[0]);
468 } catch (NumberFormatException nfe) {
469 Log.e(TAG, String.format("Error parsing code %s", tok[0]));
470 return false;
471 }
472 if (code == VoldResponseCode.ShareStatusResult) {
473 if (tok[2].equals("available"))
474 return true;
475 return false;
476 } else {
477 Log.e(TAG, String.format("Unexpected response code %d", code));
478 return false;
479 }
480 }
481 Log.e(TAG, "Got an empty response");
482 return false;
483 }
484
485 private int doMountVolume(String path) {
San Mehatb1043402010-02-05 08:26:50 -0800486 int rc = StorageResultCode.OperationSucceeded;
San Mehat207e5382010-02-04 20:46:54 -0800487
488 try {
489 mConnector.doCommand(String.format("volume mount %s", path));
490 } catch (NativeDaemonConnectorException e) {
491 /*
492 * Mount failed for some reason
493 */
494 Intent in = null;
495 int code = e.getCode();
496 if (code == VoldResponseCode.OpFailedNoMedia) {
497 /*
498 * Attempt to mount but no media inserted
499 */
San Mehatb1043402010-02-05 08:26:50 -0800500 rc = StorageResultCode.OperationFailedNoMedia;
San Mehat207e5382010-02-04 20:46:54 -0800501 } else if (code == VoldResponseCode.OpFailedMediaBlank) {
502 /*
503 * Media is blank or does not contain a supported filesystem
504 */
505 updatePublicVolumeState(path, Environment.MEDIA_NOFS);
506 in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path));
San Mehatb1043402010-02-05 08:26:50 -0800507 rc = StorageResultCode.OperationFailedMediaBlank;
San Mehat207e5382010-02-04 20:46:54 -0800508 } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
509 /*
510 * Volume consistency check failed
511 */
512 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
513 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path));
San Mehatb1043402010-02-05 08:26:50 -0800514 rc = StorageResultCode.OperationFailedMediaCorrupt;
San Mehat207e5382010-02-04 20:46:54 -0800515 } else {
San Mehatb1043402010-02-05 08:26:50 -0800516 rc = StorageResultCode.OperationFailedInternalError;
San Mehat207e5382010-02-04 20:46:54 -0800517 }
518
519 /*
520 * Send broadcast intent (if required for the failure)
521 */
522 if (in != null) {
523 mContext.sendBroadcast(in);
524 }
525 }
526
527 return rc;
528 }
529
San Mehatd9709982010-02-18 11:43:03 -0800530 private int doUnmountVolume(String path, boolean force) {
San Mehat59443a62010-02-09 13:28:45 -0800531 if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
San Mehat207e5382010-02-04 20:46:54 -0800532 return VoldResponseCode.OpFailedVolNotMounted;
533 }
534
535 // Notify PackageManager of potential media removal and deal with
536 // return code later on. The caller of this api should be aware or have been
537 // notified that the applications installed on the media will be killed.
538 mPms.updateExternalMediaStatus(false);
539 try {
San Mehatd9709982010-02-18 11:43:03 -0800540 mConnector.doCommand(String.format(
541 "volume unmount %s%s", path, (force ? " force" : "")));
San Mehatb1043402010-02-05 08:26:50 -0800542 return StorageResultCode.OperationSucceeded;
San Mehat207e5382010-02-04 20:46:54 -0800543 } catch (NativeDaemonConnectorException e) {
544 // Don't worry about mismatch in PackageManager since the
545 // call back will handle the status changes any way.
546 int code = e.getCode();
547 if (code == VoldResponseCode.OpFailedVolNotMounted) {
San Mehata181b212010-02-11 06:50:20 -0800548 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehatd9709982010-02-18 11:43:03 -0800549 } else if (code == VoldResponseCode.OpFailedStorageBusy) {
550 return StorageResultCode.OperationFailedStorageBusy;
San Mehat207e5382010-02-04 20:46:54 -0800551 } else {
San Mehatb1043402010-02-05 08:26:50 -0800552 return StorageResultCode.OperationFailedInternalError;
San Mehat207e5382010-02-04 20:46:54 -0800553 }
554 }
555 }
556
557 private int doFormatVolume(String path) {
558 try {
559 String cmd = String.format("volume format %s", path);
560 mConnector.doCommand(cmd);
San Mehatb1043402010-02-05 08:26:50 -0800561 return StorageResultCode.OperationSucceeded;
San Mehat207e5382010-02-04 20:46:54 -0800562 } catch (NativeDaemonConnectorException e) {
563 int code = e.getCode();
564 if (code == VoldResponseCode.OpFailedNoMedia) {
San Mehatb1043402010-02-05 08:26:50 -0800565 return StorageResultCode.OperationFailedNoMedia;
San Mehat207e5382010-02-04 20:46:54 -0800566 } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
San Mehatb1043402010-02-05 08:26:50 -0800567 return StorageResultCode.OperationFailedMediaCorrupt;
San Mehat207e5382010-02-04 20:46:54 -0800568 } else {
San Mehatb1043402010-02-05 08:26:50 -0800569 return StorageResultCode.OperationFailedInternalError;
San Mehat207e5382010-02-04 20:46:54 -0800570 }
571 }
572 }
573
San Mehatb1043402010-02-05 08:26:50 -0800574 private boolean doGetVolumeShared(String path, String method) {
575 String cmd = String.format("volume shared %s %s", path, method);
576 ArrayList<String> rsp = mConnector.doCommand(cmd);
577
578 for (String line : rsp) {
579 String []tok = line.split(" ");
580 int code;
581 try {
582 code = Integer.parseInt(tok[0]);
583 } catch (NumberFormatException nfe) {
584 Log.e(TAG, String.format("Error parsing code %s", tok[0]));
585 return false;
586 }
587 if (code == VoldResponseCode.ShareEnabledResult) {
588 if (tok[2].equals("enabled"))
589 return true;
590 return false;
591 } else {
592 Log.e(TAG, String.format("Unexpected response code %d", code));
593 return false;
594 }
595 }
596 Log.e(TAG, "Got an empty response");
597 return false;
598 }
599
San Mehat207e5382010-02-04 20:46:54 -0800600 private void notifyShareAvailabilityChange(String method, final boolean avail) {
San Mehat4270e1e2010-01-29 05:32:19 -0800601 if (!method.equals("ums")) {
602 Log.w(TAG, "Ignoring unsupported share method {" + method + "}");
603 return;
604 }
605
606 synchronized (mListeners) {
607 for (int i = mListeners.size() -1; i >= 0; i--) {
608 MountServiceBinderListener bl = mListeners.get(i);
609 try {
San Mehatb1043402010-02-05 08:26:50 -0800610 bl.mListener.onUsbMassStorageConnectionChanged(avail);
San Mehat4270e1e2010-01-29 05:32:19 -0800611 } catch (RemoteException rex) {
612 Log.e(TAG, "Listener dead");
613 mListeners.remove(i);
614 } catch (Exception ex) {
615 Log.e(TAG, "Listener failed", ex);
616 }
617 }
618 }
619
San Mehat207e5382010-02-04 20:46:54 -0800620 if (mBooted == true) {
621 Intent intent;
622 if (avail) {
623 intent = new Intent(Intent.ACTION_UMS_CONNECTED);
624 } else {
625 intent = new Intent(Intent.ACTION_UMS_DISCONNECTED);
626 }
627 mContext.sendBroadcast(intent);
San Mehat4270e1e2010-01-29 05:32:19 -0800628 }
San Mehat4270e1e2010-01-29 05:32:19 -0800629 }
630
San Mehat207e5382010-02-04 20:46:54 -0800631 private void validatePermission(String perm) {
San Mehat4270e1e2010-01-29 05:32:19 -0800632 if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
633 throw new SecurityException(String.format("Requires %s permission", perm));
634 }
635 }
636
637 /**
San Mehat207e5382010-02-04 20:46:54 -0800638 * Constructs a new MountService instance
639 *
640 * @param context Binder context for this service
641 */
642 public MountService(Context context) {
643 mContext = context;
644
645 /*
646 * Vold does not run in the simulator, so fake out a mounted
647 * event to trigger MediaScanner
648 */
649 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
650 updatePublicVolumeState("/sdcard", Environment.MEDIA_MOUNTED);
651 return;
652 }
653
654 // XXX: This will go away soon in favor of IMountServiceObserver
655 mPms = (PackageManagerService) ServiceManager.getService("package");
656
657 mContext.registerReceiver(mBroadcastReceiver,
658 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
659
660 mListeners = new ArrayList<MountServiceBinderListener>();
661
662 mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
663 mReady = false;
664 Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
665 thread.start();
666 }
667
668 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800669 * Exposed API calls below here
670 */
671
672 public void registerListener(IMountServiceListener listener) {
673 synchronized (mListeners) {
674 MountServiceBinderListener bl = new MountServiceBinderListener(listener);
675 try {
676 listener.asBinder().linkToDeath(bl, 0);
677 mListeners.add(bl);
678 } catch (RemoteException rex) {
679 Log.e(TAG, "Failed to link to listener death");
680 }
681 }
682 }
683
684 public void unregisterListener(IMountServiceListener listener) {
685 synchronized (mListeners) {
686 for(MountServiceBinderListener bl : mListeners) {
687 if (bl.mListener == listener) {
688 mListeners.remove(mListeners.indexOf(bl));
689 return;
690 }
691 }
692 }
693 }
694
695 public void shutdown() {
696 validatePermission(android.Manifest.permission.SHUTDOWN);
697
698 Log.i(TAG, "Shutting down");
699
700 String path = Environment.getExternalStorageDirectory().getPath();
701 String state = getVolumeState(path);
San Mehat91c77612010-01-07 10:39:41 -0800702
703 if (state.equals(Environment.MEDIA_SHARED)) {
704 /*
705 * If the media is currently shared, unshare it.
706 * XXX: This is still dangerous!. We should not
707 * be rebooting at *all* if UMS is enabled, since
708 * the UMS host could have dirty FAT cache entries
709 * yet to flush.
710 */
San Mehatb1043402010-02-05 08:26:50 -0800711 if (setUsbMassStorageEnabled(false) != StorageResultCode.OperationSucceeded) {
San Mehat4270e1e2010-01-29 05:32:19 -0800712 Log.e(TAG, "UMS disable on shutdown failed");
San Mehat91c77612010-01-07 10:39:41 -0800713 }
714 } else if (state.equals(Environment.MEDIA_CHECKING)) {
715 /*
716 * If the media is being checked, then we need to wait for
717 * it to complete before being able to proceed.
718 */
719 // XXX: @hackbod - Should we disable the ANR timer here?
720 int retries = 30;
721 while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
722 try {
723 Thread.sleep(1000);
724 } catch (InterruptedException iex) {
725 Log.e(TAG, "Interrupted while waiting for media", iex);
726 break;
727 }
728 state = Environment.getExternalStorageState();
729 }
730 if (retries == 0) {
731 Log.e(TAG, "Timed out waiting for media to check");
732 }
733 }
734
735 if (state.equals(Environment.MEDIA_MOUNTED)) {
736 /*
737 * If the media is mounted, then gracefully unmount it.
738 */
San Mehatd9709982010-02-18 11:43:03 -0800739 if (doUnmountVolume(path, true) != StorageResultCode.OperationSucceeded) {
San Mehat4270e1e2010-01-29 05:32:19 -0800740 Log.e(TAG, "Failed to unmount media for shutdown");
741 }
742 }
743 }
744
San Mehatb1043402010-02-05 08:26:50 -0800745 public boolean isUsbMassStorageConnected() {
San Mehat207e5382010-02-04 20:46:54 -0800746 waitForReady();
San Mehat91c77612010-01-07 10:39:41 -0800747
San Mehatb1043402010-02-05 08:26:50 -0800748 if (mUmsEnabling) {
749 return true;
San Mehat7fd0fee2009-12-17 07:12:23 -0800750 }
San Mehatb1043402010-02-05 08:26:50 -0800751 return doGetShareMethodAvailable("ums");
752 }
753
754 public int setUsbMassStorageEnabled(boolean enable) {
755 waitForReady();
756
757 return doShareUnshareVolume(Environment.getExternalStorageDirectory().getPath(), "ums", enable);
758 }
759
760 public boolean isUsbMassStorageEnabled() {
761 waitForReady();
762 return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 }
San Mehat4270e1e2010-01-29 05:32:19 -0800764
San Mehat7fd0fee2009-12-17 07:12:23 -0800765 /**
766 * @return state of the volume at the specified mount point
767 */
San Mehat4270e1e2010-01-29 05:32:19 -0800768 public String getVolumeState(String mountPoint) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800769 /*
770 * XXX: Until we have multiple volume discovery, just hardwire
771 * this to /sdcard
772 */
773 if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
774 Log.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
775 throw new IllegalArgumentException();
776 }
777
778 return mLegacyState;
779 }
780
San Mehat4270e1e2010-01-29 05:32:19 -0800781 public int mountVolume(String path) {
782 validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehat4270e1e2010-01-29 05:32:19 -0800783
San Mehat207e5382010-02-04 20:46:54 -0800784 waitForReady();
785 return doMountVolume(path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 }
787
San Mehatd9709982010-02-18 11:43:03 -0800788 public int unmountVolume(String path, boolean force) {
San Mehat4270e1e2010-01-29 05:32:19 -0800789 validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -0800790 waitForReady();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791
San Mehatd9709982010-02-18 11:43:03 -0800792 return doUnmountVolume(path, force);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 }
794
San Mehat4270e1e2010-01-29 05:32:19 -0800795 public int formatVolume(String path) {
796 validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -0800797 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -0800798
San Mehat207e5382010-02-04 20:46:54 -0800799 return doFormatVolume(path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 }
801
San Mehatc1b4ce92010-02-16 17:13:03 -0800802 public int []getStorageUsers(String path) {
803 validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
804 waitForReady();
805 try {
806 String[] r = mConnector.doListCommand(
807 String.format("storage users %s", path),
808 VoldResponseCode.StorageUsersListResult);
809 // FMT: <pid> <process name>
810 int[] data = new int[r.length];
811 for (int i = 0; i < r.length; i++) {
812 String []tok = r[i].split(" ");
813 try {
814 data[i] = Integer.parseInt(tok[0]);
815 } catch (NumberFormatException nfe) {
816 Log.e(TAG, String.format("Error parsing pid %s", tok[0]));
817 return new int[0];
818 }
819 }
820 return data;
821 } catch (NativeDaemonConnectorException e) {
822 Log.e(TAG, "Failed to retrieve storage users list", e);
823 return new int[0];
824 }
825 }
826
San Mehatb1043402010-02-05 08:26:50 -0800827 private void warnOnNotMounted() {
828 if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
829 Log.w(TAG, "getSecureContainerList() called when storage not mounted");
830 }
831 }
832
San Mehat4270e1e2010-01-29 05:32:19 -0800833 public String[] getSecureContainerList() {
834 validatePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -0800835 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800836 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -0800837
San Mehat4270e1e2010-01-29 05:32:19 -0800838 try {
839 return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult);
840 } catch (NativeDaemonConnectorException e) {
841 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 }
843 }
San Mehat36972292010-01-06 11:06:32 -0800844
San Mehat4270e1e2010-01-29 05:32:19 -0800845 public int createSecureContainer(String id, int sizeMb, String fstype,
846 String key, int ownerUid) {
847 validatePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -0800848 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800849 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800850
San Mehatb1043402010-02-05 08:26:50 -0800851 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800852 String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid);
853 try {
854 mConnector.doCommand(cmd);
855 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -0800856 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -0800857 }
San Mehata181b212010-02-11 06:50:20 -0800858
859 if (rc == StorageResultCode.OperationSucceeded) {
860 synchronized (mAsecMountSet) {
861 mAsecMountSet.add(id);
862 }
863 }
San Mehat4270e1e2010-01-29 05:32:19 -0800864 return rc;
San Mehat36972292010-01-06 11:06:32 -0800865 }
866
San Mehat4270e1e2010-01-29 05:32:19 -0800867 public int finalizeSecureContainer(String id) {
868 validatePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -0800869 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800870
San Mehatb1043402010-02-05 08:26:50 -0800871 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800872 try {
873 mConnector.doCommand(String.format("asec finalize %s", id));
San Mehata181b212010-02-11 06:50:20 -0800874 /*
875 * Finalization does a remount, so no need
876 * to update mAsecMountSet
877 */
San Mehat4270e1e2010-01-29 05:32:19 -0800878 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -0800879 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -0800880 }
San Mehat4270e1e2010-01-29 05:32:19 -0800881 return rc;
San Mehat36972292010-01-06 11:06:32 -0800882 }
883
San Mehatd9709982010-02-18 11:43:03 -0800884 public int destroySecureContainer(String id, boolean force) {
San Mehat4270e1e2010-01-29 05:32:19 -0800885 validatePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -0800886 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800887 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -0800888
San Mehatb1043402010-02-05 08:26:50 -0800889 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800890 try {
San Mehatd9709982010-02-18 11:43:03 -0800891 mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
San Mehat4270e1e2010-01-29 05:32:19 -0800892 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -0800893 int code = e.getCode();
894 if (code == VoldResponseCode.OpFailedStorageBusy) {
895 rc = StorageResultCode.OperationFailedStorageBusy;
896 } else {
897 rc = StorageResultCode.OperationFailedInternalError;
898 }
San Mehat02735bc2010-01-26 15:18:08 -0800899 }
San Mehata181b212010-02-11 06:50:20 -0800900
901 if (rc == StorageResultCode.OperationSucceeded) {
902 synchronized (mAsecMountSet) {
903 if (mAsecMountSet.contains(id)) {
904 mAsecMountSet.remove(id);
905 }
906 }
907 }
908
San Mehat4270e1e2010-01-29 05:32:19 -0800909 return rc;
San Mehat36972292010-01-06 11:06:32 -0800910 }
911
San Mehat4270e1e2010-01-29 05:32:19 -0800912 public int mountSecureContainer(String id, String key, int ownerUid) {
913 validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -0800914 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800915 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800916
San Mehata181b212010-02-11 06:50:20 -0800917 synchronized (mAsecMountSet) {
918 if (mAsecMountSet.contains(id)) {
919 return StorageResultCode.OperationFailedStorageMounted;
920 }
921 }
922
San Mehatb1043402010-02-05 08:26:50 -0800923 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800924 String cmd = String.format("asec mount %s %s %d", id, key, ownerUid);
925 try {
926 mConnector.doCommand(cmd);
927 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -0800928 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -0800929 }
San Mehat6cdd9c02010-02-09 14:45:20 -0800930
931 if (rc == StorageResultCode.OperationSucceeded) {
932 synchronized (mAsecMountSet) {
933 mAsecMountSet.add(id);
934 }
935 }
San Mehat4270e1e2010-01-29 05:32:19 -0800936 return rc;
San Mehat36972292010-01-06 11:06:32 -0800937 }
938
San Mehatd9709982010-02-18 11:43:03 -0800939 public int unmountSecureContainer(String id, boolean force) {
San Mehat4270e1e2010-01-29 05:32:19 -0800940 validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -0800941 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800942 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800943
San Mehat6cdd9c02010-02-09 14:45:20 -0800944 synchronized (mAsecMountSet) {
945 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -0800946 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -0800947 }
948 }
949
San Mehatb1043402010-02-05 08:26:50 -0800950 int rc = StorageResultCode.OperationSucceeded;
San Mehatd9709982010-02-18 11:43:03 -0800951 String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
San Mehat4270e1e2010-01-29 05:32:19 -0800952 try {
953 mConnector.doCommand(cmd);
954 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -0800955 int code = e.getCode();
956 if (code == VoldResponseCode.OpFailedStorageBusy) {
957 rc = StorageResultCode.OperationFailedStorageBusy;
958 } else {
959 rc = StorageResultCode.OperationFailedInternalError;
960 }
San Mehat02735bc2010-01-26 15:18:08 -0800961 }
San Mehat6cdd9c02010-02-09 14:45:20 -0800962
963 if (rc == StorageResultCode.OperationSucceeded) {
964 synchronized (mAsecMountSet) {
965 mAsecMountSet.remove(id);
966 }
967 }
San Mehat4270e1e2010-01-29 05:32:19 -0800968 return rc;
San Mehat9dba7092010-01-18 06:47:41 -0800969 }
970
San Mehat6cdd9c02010-02-09 14:45:20 -0800971 public boolean isSecureContainerMounted(String id) {
972 validatePermission(android.Manifest.permission.ASEC_ACCESS);
973 waitForReady();
974 warnOnNotMounted();
975
976 synchronized (mAsecMountSet) {
977 return mAsecMountSet.contains(id);
978 }
979 }
980
San Mehat4270e1e2010-01-29 05:32:19 -0800981 public int renameSecureContainer(String oldId, String newId) {
982 validatePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -0800983 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -0800984 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -0800985
San Mehata181b212010-02-11 06:50:20 -0800986 synchronized (mAsecMountSet) {
987 if (mAsecMountSet.contains(oldId)) {
988 return StorageResultCode.OperationFailedStorageMounted;
989 }
990 }
991
San Mehatb1043402010-02-05 08:26:50 -0800992 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -0800993 String cmd = String.format("asec rename %s %s", oldId, newId);
994 try {
995 mConnector.doCommand(cmd);
996 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -0800997 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -0800998 }
San Mehata181b212010-02-11 06:50:20 -0800999
San Mehat4270e1e2010-01-29 05:32:19 -08001000 return rc;
San Mehat45f61042010-01-23 08:12:43 -08001001 }
1002
San Mehat4270e1e2010-01-29 05:32:19 -08001003 public String getSecureContainerPath(String id) {
1004 validatePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08001005 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001006 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08001007
San Mehat4270e1e2010-01-29 05:32:19 -08001008 ArrayList<String> rsp = mConnector.doCommand("asec path " + id);
San Mehat36972292010-01-06 11:06:32 -08001009
San Mehat22dd86e2010-01-12 12:21:18 -08001010 for (String line : rsp) {
1011 String []tok = line.split(" ");
1012 int code = Integer.parseInt(tok[0]);
1013 if (code == VoldResponseCode.AsecPathResult) {
1014 return tok[1];
1015 } else {
San Mehat4270e1e2010-01-29 05:32:19 -08001016 Log.e(TAG, String.format("Unexpected response code %d", code));
1017 return "";
San Mehat22dd86e2010-01-12 12:21:18 -08001018 }
1019 }
San Mehat4270e1e2010-01-29 05:32:19 -08001020
1021 Log.e(TAG, "Got an empty response");
1022 return "";
San Mehat22dd86e2010-01-12 12:21:18 -08001023 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024}
1025