blob: c8a691526058318cf7e531eeaf8fef8b7b1ce2a6 [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
19import android.app.Notification;
20import android.app.NotificationManager;
21import android.app.PendingIntent;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.pm.PackageManager;
27import android.content.res.Resources;
28import android.net.Uri;
29import android.os.IMountService;
30import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.os.SystemProperties;
32import android.os.UEventObserver;
San Mehat1f6301e2010-01-07 22:40:27 -080033import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.text.TextUtils;
35import android.util.Log;
San Mehat22dd86e2010-01-12 12:21:18 -080036import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037
San Mehat1f6301e2010-01-07 22:40:27 -080038import android.provider.Settings;
39import android.content.ContentResolver;
40import android.database.ContentObserver;
41
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import java.io.File;
43import java.io.FileReader;
San Mehat36972292010-01-06 11:06:32 -080044import java.lang.IllegalStateException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045
46/**
47 * MountService implements an to the mount service daemon
48 * @hide
49 */
San Mehat22dd86e2010-01-12 12:21:18 -080050class MountService extends IMountService.Stub
51 implements INativeDaemonConnectorCallbacks {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052
53 private static final String TAG = "MountService";
54
San Mehat7fd0fee2009-12-17 07:12:23 -080055 class VolumeState {
56 public static final int Init = -1;
57 public static final int NoMedia = 0;
58 public static final int Idle = 1;
59 public static final int Pending = 2;
60 public static final int Checking = 3;
61 public static final int Mounted = 4;
62 public static final int Unmounting = 5;
63 public static final int Formatting = 6;
64 public static final int Shared = 7;
65 public static final int SharedMnt = 8;
66 }
67
San Mehat22dd86e2010-01-12 12:21:18 -080068 class VoldResponseCode {
69 public static final int VolumeListResult = 110;
70 public static final int AsecListResult = 111;
71
72 public static final int ShareAvailabilityResult = 210;
73 public static final int AsecPathResult = 211;
74
75 public static final int VolumeStateChange = 605;
76 public static final int VolumeMountFailedBlank = 610;
77 public static final int VolumeMountFailedDamaged = 611;
78 public static final int VolumeMountFailedNoMedia = 612;
79 public static final int ShareAvailabilityChange = 620;
80 public static final int VolumeDiskInserted = 630;
81 public static final int VolumeDiskRemoved = 631;
82 public static final int VolumeBadRemoval = 632;
83 }
84
85
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 /**
87 * Binder context for this service
88 */
89 private Context mContext;
90
91 /**
San Mehat22dd86e2010-01-12 12:21:18 -080092 * connectorr object for communicating with vold
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 */
San Mehat22dd86e2010-01-12 12:21:18 -080094 private NativeDaemonConnector mConnector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
96 /**
97 * The notification that is shown when a USB mass storage host
98 * is connected.
99 * <p>
100 * This is lazily created, so use {@link #setUsbStorageNotification()}.
101 */
102 private Notification mUsbStorageNotification;
103
104
105 /**
106 * The notification that is shown when the following media events occur:
107 * - Media is being checked
108 * - Media is blank (or unknown filesystem)
109 * - Media is corrupt
110 * - Media is safe to unmount
111 * - Media is missing
112 * <p>
113 * This is lazily created, so use {@link #setMediaStorageNotification()}.
114 */
115 private Notification mMediaStorageNotification;
116
117 private boolean mShowSafeUnmountNotificationWhenUnmounted;
118
119 private boolean mPlaySounds;
120
121 private boolean mMounted;
122
San Mehat1f6301e2010-01-07 22:40:27 -0800123 private SettingsWatcher mSettingsWatcher;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700124 private boolean mAutoStartUms;
San Mehat1f6301e2010-01-07 22:40:27 -0800125 private boolean mPromptUms;
126 private boolean mUmsActiveNotify;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700127
San Mehat7fd0fee2009-12-17 07:12:23 -0800128 private boolean mUmsConnected = false;
129 private boolean mUmsEnabled = false;
130
131 private String mLegacyState = Environment.MEDIA_REMOVED;
132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 /**
134 * Constructs a new MountService instance
135 *
136 * @param context Binder context for this service
137 */
138 public MountService(Context context) {
139 mContext = context;
140
141 // Register a BOOT_COMPLETED handler so that we can start
San Mehat22dd86e2010-01-12 12:21:18 -0800142 // our NativeDaemonConnector. We defer the startup so that we don't
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 // start processing events before we ought-to
144 mContext.registerReceiver(mBroadcastReceiver,
145 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
146
San Mehat22dd86e2010-01-12 12:21:18 -0800147 mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 mShowSafeUnmountNotificationWhenUnmounted = false;
149
150 mPlaySounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700151
San Mehat1f6301e2010-01-07 22:40:27 -0800152 ContentResolver cr = mContext.getContentResolver();
153 mAutoStartUms = (Settings.Secure.getInt(
154 cr, Settings.Secure.MOUNT_UMS_AUTOSTART, 0) == 1);
155 mPromptUms = (Settings.Secure.getInt(
156 cr, Settings.Secure.MOUNT_UMS_PROMPT, 1) == 1);
157 mUmsActiveNotify = (Settings.Secure.getInt(
158 cr, Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED, 1) == 1);
159
160 mSettingsWatcher = new SettingsWatcher(new Handler());
161 }
162
163 private class SettingsWatcher extends ContentObserver {
164 public SettingsWatcher(Handler handler) {
165 super(handler);
166 ContentResolver cr = mContext.getContentResolver();
167 cr.registerContentObserver(Settings.System.getUriFor(
168 Settings.Secure.MOUNT_PLAY_NOTIFICATION_SND), false, this);
169 cr.registerContentObserver(Settings.Secure.getUriFor(
170 Settings.Secure.MOUNT_UMS_AUTOSTART), false, this);
171 cr.registerContentObserver(Settings.Secure.getUriFor(
172 Settings.Secure.MOUNT_UMS_PROMPT), false, this);
173 cr.registerContentObserver(Settings.Secure.getUriFor(
174 Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED), false, this);
175 }
176
177 public void onChange(boolean selfChange) {
178 super.onChange(selfChange);
179 ContentResolver cr = mContext.getContentResolver();
180
181 boolean newPlayNotificationSounds = (Settings.Secure.getInt(
182 cr, Settings.Secure.MOUNT_PLAY_NOTIFICATION_SND, 1) == 1);
183
184 boolean newUmsAutostart = (Settings.Secure.getInt(
185 cr, Settings.Secure.MOUNT_UMS_AUTOSTART, 0) == 1);
186
187 if (newUmsAutostart != mAutoStartUms) {
San Mehat1f6301e2010-01-07 22:40:27 -0800188 mAutoStartUms = newUmsAutostart;
189 }
190
191 boolean newUmsPrompt = (Settings.Secure.getInt(
192 cr, Settings.Secure.MOUNT_UMS_PROMPT, 1) == 1);
193
194 if (newUmsPrompt != mPromptUms) {
San Mehat1f6301e2010-01-07 22:40:27 -0800195 mPromptUms = newUmsAutostart;
196 }
197
198 boolean newUmsNotifyEnabled = (Settings.Secure.getInt(
199 cr, Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED, 1) == 1);
200
San Mehat1f6301e2010-01-07 22:40:27 -0800201 if (mUmsEnabled) {
202 if (newUmsNotifyEnabled) {
203 Intent intent = new Intent();
204 intent.setClass(mContext, com.android.internal.app.UsbStorageStopActivity.class);
205 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
206 setUsbStorageNotification(com.android.internal.R.string.usb_storage_stop_notification_title,
207 com.android.internal.R.string.usb_storage_stop_notification_message,
208 com.android.internal.R.drawable.stat_sys_warning,
209 false, true, pi);
210 } else {
211 setUsbStorageNotification(0, 0, 0, false, false, null);
212 }
213 }
214 if (newUmsNotifyEnabled != mUmsActiveNotify) {
San Mehat1f6301e2010-01-07 22:40:27 -0800215 mUmsActiveNotify = newUmsNotifyEnabled;
216 }
217 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 }
219
220 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
221 public void onReceive(Context context, Intent intent) {
San Mehat91c77612010-01-07 10:39:41 -0800222 String action = intent.getAction();
223
224 if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
San Mehat22dd86e2010-01-12 12:21:18 -0800225 /*
226 * Vold does not run in the simulator, so fake out a mounted
227 * event to trigger MediaScanner
228 */
229 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
230 notifyMediaMounted(
231 Environment.getExternalStorageDirectory().getPath(), false);
232 return;
233 }
234
235 Thread thread = new Thread(
236 mConnector, NativeDaemonConnector.class.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 thread.start();
238 }
239 }
240 };
241
San Mehat91c77612010-01-07 10:39:41 -0800242 public void shutdown() {
243 if (mContext.checkCallingOrSelfPermission(
244 android.Manifest.permission.SHUTDOWN)
245 != PackageManager.PERMISSION_GRANTED) {
246 throw new SecurityException("Requires SHUTDOWN permission");
247 }
248
San Mehat7ebf0172010-01-12 07:57:42 -0800249 Log.d(TAG, "Shutting down");
San Mehat91c77612010-01-07 10:39:41 -0800250 String state = Environment.getExternalStorageState();
251
252 if (state.equals(Environment.MEDIA_SHARED)) {
253 /*
254 * If the media is currently shared, unshare it.
255 * XXX: This is still dangerous!. We should not
256 * be rebooting at *all* if UMS is enabled, since
257 * the UMS host could have dirty FAT cache entries
258 * yet to flush.
259 */
260 try {
261 setMassStorageEnabled(false);
262 } catch (Exception e) {
263 Log.e(TAG, "ums disable failed", e);
264 }
265 } else if (state.equals(Environment.MEDIA_CHECKING)) {
266 /*
267 * If the media is being checked, then we need to wait for
268 * it to complete before being able to proceed.
269 */
270 // XXX: @hackbod - Should we disable the ANR timer here?
271 int retries = 30;
272 while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
273 try {
274 Thread.sleep(1000);
275 } catch (InterruptedException iex) {
276 Log.e(TAG, "Interrupted while waiting for media", iex);
277 break;
278 }
279 state = Environment.getExternalStorageState();
280 }
281 if (retries == 0) {
282 Log.e(TAG, "Timed out waiting for media to check");
283 }
284 }
285
286 if (state.equals(Environment.MEDIA_MOUNTED)) {
287 /*
288 * If the media is mounted, then gracefully unmount it.
289 */
290 try {
291 String m = Environment.getExternalStorageDirectory().toString();
San Mehat22dd86e2010-01-12 12:21:18 -0800292 unmountVolume(m);
San Mehat7ebf0172010-01-12 07:57:42 -0800293
294 int retries = 12;
295 while (!state.equals(Environment.MEDIA_UNMOUNTED) && (retries-- >=0)) {
296 try {
297 Thread.sleep(1000);
298 } catch (InterruptedException iex) {
299 Log.e(TAG, "Interrupted while waiting for media", iex);
300 break;
301 }
302 state = Environment.getExternalStorageState();
303 }
304 if (retries == 0) {
305 Log.e(TAG, "Timed out waiting for media to unmount");
Jean-Baptiste Querufa101532010-01-12 11:53:42 -0800306 }
San Mehat91c77612010-01-07 10:39:41 -0800307 } catch (Exception e) {
308 Log.e(TAG, "external storage unmount failed", e);
309 }
310 }
311 }
312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 /**
314 * @return true if USB mass storage support is enabled.
315 */
San Mehat36972292010-01-06 11:06:32 -0800316 public boolean getMassStorageEnabled() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800317 return mUmsEnabled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 }
319
320 /**
321 * Enables or disables USB mass storage support.
322 *
323 * @param enable true to enable USB mass storage support
324 */
San Mehat36972292010-01-06 11:06:32 -0800325 public void setMassStorageEnabled(boolean enable) throws IllegalStateException {
San Mehat1f6301e2010-01-07 22:40:27 -0800326 if (mContext.checkCallingOrSelfPermission(
327 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
328 != PackageManager.PERMISSION_GRANTED) {
329 throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
330 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800331 try {
332 String vp = Environment.getExternalStorageDirectory().getPath();
333 String vs = getVolumeState(vp);
334
335 if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
San Mehat22dd86e2010-01-12 12:21:18 -0800336 unmountVolume(vp);
San Mehat1f6301e2010-01-07 22:40:27 -0800337 updateUsbMassStorageNotification(true, false);
San Mehat7fd0fee2009-12-17 07:12:23 -0800338 }
339
San Mehat22dd86e2010-01-12 12:21:18 -0800340 setShareMethodEnabled(vp, "ums", enable);
San Mehat7fd0fee2009-12-17 07:12:23 -0800341 mUmsEnabled = enable;
342 if (!enable) {
San Mehat22dd86e2010-01-12 12:21:18 -0800343 mountVolume(vp);
San Mehat1f6301e2010-01-07 22:40:27 -0800344 if (mPromptUms) {
345 updateUsbMassStorageNotification(false, false);
346 } else {
347 updateUsbMassStorageNotification(true, false);
348 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800349 }
San Mehat36972292010-01-06 11:06:32 -0800350 } catch (IllegalStateException rex) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800351 Log.e(TAG, "Failed to set ums enable {" + enable + "}");
352 return;
353 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 }
355
356 /**
357 * @return true if USB mass storage is connected.
358 */
San Mehat36972292010-01-06 11:06:32 -0800359 public boolean getMassStorageConnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800360 return mUmsConnected;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800362
363 /**
364 * @return state of the volume at the specified mount point
365 */
San Mehat36972292010-01-06 11:06:32 -0800366 public String getVolumeState(String mountPoint) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800367 /*
368 * XXX: Until we have multiple volume discovery, just hardwire
369 * this to /sdcard
370 */
371 if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
372 Log.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
373 throw new IllegalArgumentException();
374 }
375
376 return mLegacyState;
377 }
378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379
380 /**
381 * Attempt to mount external media
382 */
San Mehat22dd86e2010-01-12 12:21:18 -0800383 public void mountVolume(String mountPath) throws IllegalStateException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 if (mContext.checkCallingOrSelfPermission(
385 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
386 != PackageManager.PERMISSION_GRANTED) {
387 throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
388 }
San Mehat22dd86e2010-01-12 12:21:18 -0800389 mConnector.doCommand(String.format("mount %s", mountPath));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 }
391
392 /**
393 * Attempt to unmount external media to prepare for eject
394 */
San Mehat22dd86e2010-01-12 12:21:18 -0800395 public void unmountVolume(String mountPath) throws IllegalStateException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 if (mContext.checkCallingOrSelfPermission(
397 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
398 != PackageManager.PERMISSION_GRANTED) {
399 throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
400 }
401
402 // Set a flag so that when we get the unmounted event, we know
403 // to display the notification
404 mShowSafeUnmountNotificationWhenUnmounted = true;
405
San Mehat22dd86e2010-01-12 12:21:18 -0800406 mConnector.doCommand(String.format("unmount %s", mountPath));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 }
408
409 /**
410 * Attempt to format external media
411 */
San Mehat22dd86e2010-01-12 12:21:18 -0800412 public void formatVolume(String formatPath) throws IllegalStateException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 if (mContext.checkCallingOrSelfPermission(
414 android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
415 != PackageManager.PERMISSION_GRANTED) {
416 throw new SecurityException("Requires MOUNT_FORMAT_FILESYSTEMS permission");
417 }
418
San Mehat22dd86e2010-01-12 12:21:18 -0800419 mConnector.doCommand(String.format("format %s", formatPath));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 }
421
San Mehat22dd86e2010-01-12 12:21:18 -0800422 boolean getShareAvailable(String method) throws IllegalStateException {
423 ArrayList<String> rsp = mConnector.doCommand("share_available " + method);
424
425 for (String line : rsp) {
426 String []tok = line.split(" ");
427 int code = Integer.parseInt(tok[0]);
428 if (code == VoldResponseCode.ShareAvailabilityResult) {
429 if (tok[2].equals("available"))
430 return true;
431 return false;
432 } else {
433 throw new IllegalStateException(String.format("Unexpected response code %d", code));
434 }
435 }
436 throw new IllegalStateException("Got an empty response");
437 }
438
439 /**
440 * Enables or disables USB mass storage support.
441 *
442 * @param enable true to enable USB mass storage support
443 */
444 void setShareMethodEnabled(String mountPoint, String method,
445 boolean enable) throws IllegalStateException {
446 mConnector.doCommand(String.format(
447 "%sshare %s %s", (enable ? "" : "un"), mountPoint, method));
448 }
449
450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 /**
452 * Returns true if we're playing media notification sounds.
453 */
454 public boolean getPlayNotificationSounds() {
455 return mPlaySounds;
456 }
457
458 /**
459 * Set whether or not we're playing media notification sounds.
460 */
461 public void setPlayNotificationSounds(boolean enabled) {
462 if (mContext.checkCallingOrSelfPermission(
463 android.Manifest.permission.WRITE_SETTINGS)
464 != PackageManager.PERMISSION_GRANTED) {
465 throw new SecurityException("Requires WRITE_SETTINGS permission");
466 }
467 mPlaySounds = enabled;
468 SystemProperties.set("persist.service.mount.playsnd", (enabled ? "1" : "0"));
469 }
470
San Mehat7fd0fee2009-12-17 07:12:23 -0800471 void updatePublicVolumeState(String mountPoint, String state) {
472 if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
473 Log.w(TAG, "Multiple volumes not currently supported");
474 return;
475 }
San Mehat22dd86e2010-01-12 12:21:18 -0800476 Log.i(TAG, "State for {" + mountPoint + "} = {" + state + "}");
San Mehat7fd0fee2009-12-17 07:12:23 -0800477 mLegacyState = state;
478 }
479
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700480 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 * Update the state of the USB mass storage notification
482 */
483 void updateUsbMassStorageNotification(boolean suppressIfConnected, boolean sound) {
484
485 try {
486
487 if (getMassStorageConnected() && !suppressIfConnected) {
488 Intent intent = new Intent();
489 intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
Mike Lockwood95174432009-08-26 09:44:09 -0700490 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
492 setUsbStorageNotification(
493 com.android.internal.R.string.usb_storage_notification_title,
494 com.android.internal.R.string.usb_storage_notification_message,
495 com.android.internal.R.drawable.stat_sys_data_usb,
496 sound, true, pi);
497 } else {
498 setUsbStorageNotification(0, 0, 0, false, false, null);
499 }
San Mehat36972292010-01-06 11:06:32 -0800500 } catch (IllegalStateException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 // Nothing to do
502 }
503 }
504
505 void handlePossibleExplicitUnmountBroadcast(String path) {
506 if (mMounted) {
507 mMounted = false;
508 Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED,
509 Uri.parse("file://" + path));
510 mContext.sendBroadcast(intent);
511 }
512 }
513
San Mehat22dd86e2010-01-12 12:21:18 -0800514 /**
515 *
516 * Callback from NativeDaemonConnector
517 */
518 public void onDaemonConnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800519 new Thread() {
520 public void run() {
521 try {
522 if (!getVolumeState(Environment.getExternalStorageDirectory().getPath())
523 .equals(Environment.MEDIA_MOUNTED)) {
524 try {
San Mehat22dd86e2010-01-12 12:21:18 -0800525 mountVolume(Environment.getExternalStorageDirectory().getPath());
San Mehat7fd0fee2009-12-17 07:12:23 -0800526 } catch (Exception ex) {
527 Log.w(TAG, "Connection-mount failed");
528 }
529 } else {
530 Log.d(TAG, "Skipping connection-mount; already mounted");
531 }
San Mehat36972292010-01-06 11:06:32 -0800532 } catch (IllegalStateException rex) {
San Mehat1f6301e2010-01-07 22:40:27 -0800533 Log.e(TAG, "Exception while handling connection mount ", rex);
San Mehat7fd0fee2009-12-17 07:12:23 -0800534 }
535
536 try {
San Mehat22dd86e2010-01-12 12:21:18 -0800537 boolean avail = getShareAvailable("ums");
San Mehat7fd0fee2009-12-17 07:12:23 -0800538 notifyShareAvailabilityChange("ums", avail);
539 } catch (Exception ex) {
540 Log.w(TAG, "Failed to get share availability");
541 }
542 }
543 }.start();
544 }
545
San Mehat22dd86e2010-01-12 12:21:18 -0800546 /**
547 *
548 * Callback from NativeDaemonConnector
549 */
550 public boolean onEvent(int code, String raw, String[] cooked) {
551 // Log.d(TAG, "event {" + raw + "}");
552 if (code == VoldResponseCode.VolumeStateChange) {
553 // FMT: NNN Volume <label> <mountpoint> state changed
554 // from <old_#> (<old_str>) to <new_#> (<new_str>)
555 notifyVolumeStateChange(
556 cooked[2], cooked[3], Integer.parseInt(cooked[7]),
557 Integer.parseInt(cooked[10]));
558 } else if (code == VoldResponseCode.VolumeMountFailedBlank) {
559 // FMT: NNN Volume <label> <mountpoint> mount failed - no supported file-systems
560 notifyMediaNoFs(cooked[3]);
561 // FMT: NNN Volume <label> <mountpoint> mount failed - no media
562 } else if (code == VoldResponseCode.VolumeMountFailedNoMedia) {
563 notifyMediaRemoved(cooked[3]);
564 } else if (code == VoldResponseCode.VolumeMountFailedDamaged) {
565 // FMT: NNN Volume <label> <mountpoint> mount failed - filesystem check failed
566 notifyMediaUnmountable(cooked[3]);
567 } else if (code == VoldResponseCode.ShareAvailabilityChange) {
568 // FMT: NNN Share method <method> now <available|unavailable>
569 boolean avail = false;
570 if (cooked[5].equals("available")) {
571 avail = true;
572 }
573 notifyShareAvailabilityChange(cooked[3], avail);
574 } else if (code == VoldResponseCode.VolumeDiskInserted) {
575 // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
576 notifyMediaInserted(cooked[3]);
577 } else if (code == VoldResponseCode.VolumeDiskRemoved) {
578 // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
579 notifyMediaRemoved(cooked[3]);
580 } else if (code == VoldResponseCode.VolumeBadRemoval) {
581 // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
582 notifyMediaBadRemoval(cooked[3]);
583 } else {
584 return false;
585 }
586 return true;
587 }
588
San Mehat7fd0fee2009-12-17 07:12:23 -0800589 void notifyVolumeStateChange(String label, String mountPoint, int oldState,
San Mehat36972292010-01-06 11:06:32 -0800590 int newState) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800591 String vs = getVolumeState(mountPoint);
592
593 if (newState == VolumeState.Init) {
594 } else if (newState == VolumeState.NoMedia) {
595 // NoMedia is handled via Disk Remove events
596 } else if (newState == VolumeState.Idle) {
597 // Don't notify if we're in BAD_REMOVAL, NOFS, or UNMOUNTABLE
598 if (!vs.equals(Environment.MEDIA_BAD_REMOVAL) &&
599 !vs.equals(Environment.MEDIA_NOFS) &&
600 !vs.equals(Environment.MEDIA_UNMOUNTABLE)) {
601 notifyMediaUnmounted(mountPoint);
602 }
603 } else if (newState == VolumeState.Pending) {
604 } else if (newState == VolumeState.Checking) {
605 notifyMediaChecking(mountPoint);
606 } else if (newState == VolumeState.Mounted) {
607 notifyMediaMounted(mountPoint, false);
608 } else if (newState == VolumeState.Unmounting) {
609 notifyMediaUnmounting(mountPoint);
610 } else if (newState == VolumeState.Formatting) {
611 } else if (newState == VolumeState.Shared) {
612 notifyMediaShared(mountPoint, false);
613 } else if (newState == VolumeState.SharedMnt) {
614 notifyMediaShared(mountPoint, true);
615 } else {
616 Log.e(TAG, "Unhandled VolumeState {" + newState + "}");
617 }
618 }
619
620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 /**
622 * Broadcasts the USB mass storage connected event to all clients.
623 */
624 void notifyUmsConnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800625 mUmsConnected = true;
626
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 String storageState = Environment.getExternalStorageState();
628 if (!storageState.equals(Environment.MEDIA_REMOVED) &&
629 !storageState.equals(Environment.MEDIA_BAD_REMOVAL) &&
630 !storageState.equals(Environment.MEDIA_CHECKING)) {
631
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700632 if (mAutoStartUms) {
633 try {
634 setMassStorageEnabled(true);
San Mehat36972292010-01-06 11:06:32 -0800635 } catch (IllegalStateException e) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700636 }
San Mehat1f6301e2010-01-07 22:40:27 -0800637 } else if (mPromptUms) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700638 updateUsbMassStorageNotification(false, true);
639 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 }
641
642 Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);
643 mContext.sendBroadcast(intent);
644 }
645
San Mehat1f6301e2010-01-07 22:40:27 -0800646 void notifyShareAvailabilityChange(String method, final boolean avail) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800647 if (!method.equals("ums")) {
648 Log.w(TAG, "Ignoring unsupported share method {" + method + "}");
649 return;
650 }
San Mehat1f6301e2010-01-07 22:40:27 -0800651
652 /*
653 * Notification needs to run in a different thread as
654 * it may need to call back into vold
655 */
656 new Thread() {
657 public void run() {
658 try {
659 if (avail) {
660 notifyUmsConnected();
661 } else {
662 notifyUmsDisconnected();
663 }
664 } catch (Exception ex) {
665 Log.w(TAG, "Failed to mount media on insertion");
666 }
667 }
668 }.start();
San Mehat7fd0fee2009-12-17 07:12:23 -0800669 }
670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 /**
672 * Broadcasts the USB mass storage disconnected event to all clients.
673 */
674 void notifyUmsDisconnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800675 mUmsConnected = false;
San Mehat1f6301e2010-01-07 22:40:27 -0800676 if (mUmsEnabled) {
677 try {
678 Log.w(TAG, "UMS disconnected while enabled!");
679 setMassStorageEnabled(false);
680 } catch (Exception ex) {
681 Log.e(TAG, "Error disabling UMS on unsafe UMS disconnect", ex);
682 }
683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 updateUsbMassStorageNotification(false, false);
685 Intent intent = new Intent(Intent.ACTION_UMS_DISCONNECTED);
686 mContext.sendBroadcast(intent);
687 }
688
San Mehat36972292010-01-06 11:06:32 -0800689 void notifyMediaInserted(final String path) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800690 new Thread() {
691 public void run() {
692 try {
San Mehat22dd86e2010-01-12 12:21:18 -0800693 mountVolume(path);
San Mehat7fd0fee2009-12-17 07:12:23 -0800694 } catch (Exception ex) {
San Mehat1f6301e2010-01-07 22:40:27 -0800695 Log.w(TAG, "Failed to mount media on insertion", ex);
San Mehat7fd0fee2009-12-17 07:12:23 -0800696 }
697 }
698 }.start();
699 }
700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 /**
702 * Broadcasts the media removed event to all clients.
703 */
San Mehat36972292010-01-06 11:06:32 -0800704 void notifyMediaRemoved(String path) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800705
706 // Suppress this on bad removal
707 if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
708 return;
709 }
710
711 updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 updateUsbMassStorageNotification(true, false);
714
715 setMediaStorageNotification(
San Mehat7fd0fee2009-12-17 07:12:23 -0800716 com.android.internal.R.string.ext_media_nomedia_notification_title,
717 com.android.internal.R.string.ext_media_nomedia_notification_message,
718 com.android.internal.R.drawable.stat_notify_sdcard_usb,
719 true, false, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 handlePossibleExplicitUnmountBroadcast(path);
721
722 Intent intent = new Intent(Intent.ACTION_MEDIA_REMOVED,
723 Uri.parse("file://" + path));
724 mContext.sendBroadcast(intent);
725 }
726
727 /**
728 * Broadcasts the media unmounted event to all clients.
729 */
730 void notifyMediaUnmounted(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800731
732 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 if (mShowSafeUnmountNotificationWhenUnmounted) {
735 setMediaStorageNotification(
736 com.android.internal.R.string.ext_media_safe_unmount_notification_title,
737 com.android.internal.R.string.ext_media_safe_unmount_notification_message,
Mike Lockwoodde46acdd2009-09-30 19:30:56 -0400738 com.android.internal.R.drawable.stat_notify_sdcard,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 true, true, null);
740 mShowSafeUnmountNotificationWhenUnmounted = false;
741 } else {
742 setMediaStorageNotification(0, 0, 0, false, false, null);
743 }
744 updateUsbMassStorageNotification(false, false);
745
746 Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED,
747 Uri.parse("file://" + path));
748 mContext.sendBroadcast(intent);
749 }
750
751 /**
752 * Broadcasts the media checking event to all clients.
753 */
754 void notifyMediaChecking(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800755 updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 setMediaStorageNotification(
758 com.android.internal.R.string.ext_media_checking_notification_title,
759 com.android.internal.R.string.ext_media_checking_notification_message,
Mike Lockwoodde46acdd2009-09-30 19:30:56 -0400760 com.android.internal.R.drawable.stat_notify_sdcard_prepare,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 true, false, null);
762
763 updateUsbMassStorageNotification(true, false);
764 Intent intent = new Intent(Intent.ACTION_MEDIA_CHECKING,
765 Uri.parse("file://" + path));
766 mContext.sendBroadcast(intent);
767 }
768
769 /**
770 * Broadcasts the media nofs event to all clients.
771 */
772 void notifyMediaNoFs(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800773 updatePublicVolumeState(path, Environment.MEDIA_NOFS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774
775 Intent intent = new Intent();
776 intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
777 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
778
779 setMediaStorageNotification(com.android.internal.R.string.ext_media_nofs_notification_title,
780 com.android.internal.R.string.ext_media_nofs_notification_message,
Mike Lockwooda7ef2692009-09-10 11:15:26 -0400781 com.android.internal.R.drawable.stat_notify_sdcard_usb,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 true, false, pi);
783 updateUsbMassStorageNotification(false, false);
784 intent = new Intent(Intent.ACTION_MEDIA_NOFS,
785 Uri.parse("file://" + path));
786 mContext.sendBroadcast(intent);
787 }
788
789 /**
790 * Broadcasts the media mounted event to all clients.
791 */
792 void notifyMediaMounted(String path, boolean readOnly) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800793 updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 setMediaStorageNotification(0, 0, 0, false, false, null);
796 updateUsbMassStorageNotification(false, false);
797 Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED,
798 Uri.parse("file://" + path));
799 intent.putExtra("read-only", readOnly);
800 mMounted = true;
801 mContext.sendBroadcast(intent);
802 }
803
804 /**
805 * Broadcasts the media shared event to all clients.
806 */
San Mehat7fd0fee2009-12-17 07:12:23 -0800807 void notifyMediaShared(String path, boolean mounted) {
808 if (mounted) {
809 Log.e(TAG, "Live shared mounts not supported yet!");
810 return;
811 }
812
813 updatePublicVolumeState(path, Environment.MEDIA_SHARED);
814
San Mehat1f6301e2010-01-07 22:40:27 -0800815 if (mUmsActiveNotify) {
816 Intent intent = new Intent();
817 intent.setClass(mContext, com.android.internal.app.UsbStorageStopActivity.class);
818 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
819 setUsbStorageNotification(com.android.internal.R.string.usb_storage_stop_notification_title,
820 com.android.internal.R.string.usb_storage_stop_notification_message,
821 com.android.internal.R.drawable.stat_sys_warning,
822 false, true, pi);
823 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 handlePossibleExplicitUnmountBroadcast(path);
San Mehat1f6301e2010-01-07 22:40:27 -0800825 Intent intent = new Intent(Intent.ACTION_MEDIA_SHARED,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 Uri.parse("file://" + path));
827 mContext.sendBroadcast(intent);
828 }
829
830 /**
831 * Broadcasts the media bad removal event to all clients.
832 */
833 void notifyMediaBadRemoval(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800834 updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 updateUsbMassStorageNotification(true, false);
837 setMediaStorageNotification(com.android.internal.R.string.ext_media_badremoval_notification_title,
838 com.android.internal.R.string.ext_media_badremoval_notification_message,
839 com.android.internal.R.drawable.stat_sys_warning,
840 true, true, null);
841
842 handlePossibleExplicitUnmountBroadcast(path);
843 Intent intent = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL,
844 Uri.parse("file://" + path));
845 mContext.sendBroadcast(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 }
847
848 /**
849 * Broadcasts the media unmountable event to all clients.
850 */
851 void notifyMediaUnmountable(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800852 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
853
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 Intent intent = new Intent();
855 intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
856 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
857
858 setMediaStorageNotification(com.android.internal.R.string.ext_media_unmountable_notification_title,
859 com.android.internal.R.string.ext_media_unmountable_notification_message,
Mike Lockwooda7ef2692009-09-10 11:15:26 -0400860 com.android.internal.R.drawable.stat_notify_sdcard_usb,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 true, false, pi);
862 updateUsbMassStorageNotification(false, false);
863
864 handlePossibleExplicitUnmountBroadcast(path);
865
866 intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE,
867 Uri.parse("file://" + path));
868 mContext.sendBroadcast(intent);
869 }
870
871 /**
872 * Broadcasts the media eject event to all clients.
873 */
San Mehat7fd0fee2009-12-17 07:12:23 -0800874 void notifyMediaUnmounting(String path) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 Intent intent = new Intent(Intent.ACTION_MEDIA_EJECT,
876 Uri.parse("file://" + path));
877 mContext.sendBroadcast(intent);
878 }
879
880 /**
881 * Sets the USB storage notification.
882 */
883 private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon, boolean sound, boolean visible,
884 PendingIntent pi) {
885
886 if (!visible && mUsbStorageNotification == null) {
887 return;
888 }
889
890 NotificationManager notificationManager = (NotificationManager) mContext
891 .getSystemService(Context.NOTIFICATION_SERVICE);
892
893 if (notificationManager == null) {
894 return;
895 }
896
897 if (visible) {
898 Resources r = Resources.getSystem();
899 CharSequence title = r.getText(titleId);
900 CharSequence message = r.getText(messageId);
901
902 if (mUsbStorageNotification == null) {
903 mUsbStorageNotification = new Notification();
904 mUsbStorageNotification.icon = icon;
905 mUsbStorageNotification.when = 0;
906 }
907
908 if (sound && mPlaySounds) {
909 mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
910 } else {
911 mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
912 }
913
914 mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
915
916 mUsbStorageNotification.tickerText = title;
917 if (pi == null) {
918 Intent intent = new Intent();
919 pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
920 }
921
922 mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
923 }
924
925 final int notificationId = mUsbStorageNotification.icon;
926 if (visible) {
927 notificationManager.notify(notificationId, mUsbStorageNotification);
928 } else {
929 notificationManager.cancel(notificationId);
930 }
931 }
932
933 private synchronized boolean getMediaStorageNotificationDismissable() {
934 if ((mMediaStorageNotification != null) &&
935 ((mMediaStorageNotification.flags & Notification.FLAG_AUTO_CANCEL) ==
936 Notification.FLAG_AUTO_CANCEL))
937 return true;
938
939 return false;
940 }
941
942 /**
943 * Sets the media storage notification.
944 */
945 private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible,
946 boolean dismissable, PendingIntent pi) {
947
948 if (!visible && mMediaStorageNotification == null) {
949 return;
950 }
951
952 NotificationManager notificationManager = (NotificationManager) mContext
953 .getSystemService(Context.NOTIFICATION_SERVICE);
954
955 if (notificationManager == null) {
956 return;
957 }
958
959 if (mMediaStorageNotification != null && visible) {
960 /*
961 * Dismiss the previous notification - we're about to
962 * re-use it.
963 */
964 final int notificationId = mMediaStorageNotification.icon;
965 notificationManager.cancel(notificationId);
966 }
967
968 if (visible) {
969 Resources r = Resources.getSystem();
970 CharSequence title = r.getText(titleId);
971 CharSequence message = r.getText(messageId);
972
973 if (mMediaStorageNotification == null) {
974 mMediaStorageNotification = new Notification();
975 mMediaStorageNotification.when = 0;
976 }
977
978 if (mPlaySounds) {
979 mMediaStorageNotification.defaults |= Notification.DEFAULT_SOUND;
980 } else {
981 mMediaStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
982 }
983
984 if (dismissable) {
985 mMediaStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
986 } else {
987 mMediaStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
988 }
989
990 mMediaStorageNotification.tickerText = title;
991 if (pi == null) {
992 Intent intent = new Intent();
993 pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
994 }
995
996 mMediaStorageNotification.icon = icon;
997 mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
998 }
999
1000 final int notificationId = mMediaStorageNotification.icon;
1001 if (visible) {
1002 notificationManager.notify(notificationId, mMediaStorageNotification);
1003 } else {
1004 notificationManager.cancel(notificationId);
1005 }
1006 }
San Mehat36972292010-01-06 11:06:32 -08001007
San Mehat0f5525a2010-01-11 10:15:16 -08001008 public String[] getSecureContainerList() throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001009 ArrayList<String> rsp = mConnector.doCommand("list_asec");
1010
1011 String[] rdata = new String[rsp.size()];
1012 int idx = 0;
1013
1014 for (String line : rsp) {
1015 String []tok = line.split(" ");
1016 int code = Integer.parseInt(tok[0]);
1017 if (code == VoldResponseCode.AsecListResult) {
1018 rdata[idx++] = tok[1];
1019 } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
1020 return rdata;
1021 } else {
1022 throw new IllegalStateException(String.format("Unexpected response code %d", code));
1023 }
1024 }
1025 throw new IllegalStateException("Got an empty response");
San Mehat36972292010-01-06 11:06:32 -08001026 }
1027
San Mehat0f5525a2010-01-11 10:15:16 -08001028 public String createSecureContainer(String id, int sizeMb, String fstype,
San Mehat36972292010-01-06 11:06:32 -08001029 String key, int ownerUid) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001030 String cmd = String.format("create_asec %s %d %s %s %d",
1031 id, sizeMb, fstype, key, ownerUid);
1032 mConnector.doCommand(cmd);
1033 return getSecureContainerPath(id);
San Mehat36972292010-01-06 11:06:32 -08001034 }
1035
San Mehat0f5525a2010-01-11 10:15:16 -08001036 public void finalizeSecureContainer(String id) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001037 mConnector.doCommand(String.format("finalize_asec %s", id));
San Mehat36972292010-01-06 11:06:32 -08001038 }
1039
San Mehat0f5525a2010-01-11 10:15:16 -08001040 public void destroySecureContainer(String id) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001041 mConnector.doCommand(String.format("destroy_asec %s", id));
San Mehat36972292010-01-06 11:06:32 -08001042 }
1043
San Mehat22dd86e2010-01-12 12:21:18 -08001044 public String mountSecureContainer(String id, String key,
1045 int ownerUid) throws IllegalStateException {
1046 String cmd = String.format("mount_asec %s %s %d",
1047 id, key, ownerUid);
1048 mConnector.doCommand(cmd);
1049 return getSecureContainerPath(id);
San Mehat36972292010-01-06 11:06:32 -08001050 }
1051
San Mehat0f5525a2010-01-11 10:15:16 -08001052 public String getSecureContainerPath(String id) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001053 ArrayList<String> rsp = mConnector.doCommand("asec_path " + id);
San Mehat36972292010-01-06 11:06:32 -08001054
San Mehat22dd86e2010-01-12 12:21:18 -08001055 for (String line : rsp) {
1056 String []tok = line.split(" ");
1057 int code = Integer.parseInt(tok[0]);
1058 if (code == VoldResponseCode.AsecPathResult) {
1059 return tok[1];
1060 } else {
1061 throw new IllegalStateException(String.format("Unexpected response code %d", code));
1062 }
1063 }
1064 throw new IllegalStateException("Got an empty response");
1065 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066}
1067