blob: f8f8742bb5cfa199e7df3c21bb80843cac65ed54 [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;
San Mehat5fbf4092010-01-15 10:13:59 -0800130 private boolean mUmsEnabling = false;
San Mehat7fd0fee2009-12-17 07:12:23 -0800131
132 private String mLegacyState = Environment.MEDIA_REMOVED;
133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 /**
135 * Constructs a new MountService instance
136 *
137 * @param context Binder context for this service
138 */
139 public MountService(Context context) {
140 mContext = context;
141
142 // Register a BOOT_COMPLETED handler so that we can start
San Mehat22dd86e2010-01-12 12:21:18 -0800143 // our NativeDaemonConnector. We defer the startup so that we don't
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 // start processing events before we ought-to
145 mContext.registerReceiver(mBroadcastReceiver,
146 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
147
San Mehat22dd86e2010-01-12 12:21:18 -0800148 mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 mShowSafeUnmountNotificationWhenUnmounted = false;
150
151 mPlaySounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700152
San Mehat1f6301e2010-01-07 22:40:27 -0800153 ContentResolver cr = mContext.getContentResolver();
154 mAutoStartUms = (Settings.Secure.getInt(
155 cr, Settings.Secure.MOUNT_UMS_AUTOSTART, 0) == 1);
156 mPromptUms = (Settings.Secure.getInt(
157 cr, Settings.Secure.MOUNT_UMS_PROMPT, 1) == 1);
158 mUmsActiveNotify = (Settings.Secure.getInt(
159 cr, Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED, 1) == 1);
160
161 mSettingsWatcher = new SettingsWatcher(new Handler());
162 }
163
164 private class SettingsWatcher extends ContentObserver {
165 public SettingsWatcher(Handler handler) {
166 super(handler);
167 ContentResolver cr = mContext.getContentResolver();
168 cr.registerContentObserver(Settings.System.getUriFor(
169 Settings.Secure.MOUNT_PLAY_NOTIFICATION_SND), false, this);
170 cr.registerContentObserver(Settings.Secure.getUriFor(
171 Settings.Secure.MOUNT_UMS_AUTOSTART), false, this);
172 cr.registerContentObserver(Settings.Secure.getUriFor(
173 Settings.Secure.MOUNT_UMS_PROMPT), false, this);
174 cr.registerContentObserver(Settings.Secure.getUriFor(
175 Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED), false, this);
176 }
177
178 public void onChange(boolean selfChange) {
179 super.onChange(selfChange);
180 ContentResolver cr = mContext.getContentResolver();
181
182 boolean newPlayNotificationSounds = (Settings.Secure.getInt(
183 cr, Settings.Secure.MOUNT_PLAY_NOTIFICATION_SND, 1) == 1);
184
185 boolean newUmsAutostart = (Settings.Secure.getInt(
186 cr, Settings.Secure.MOUNT_UMS_AUTOSTART, 0) == 1);
187
188 if (newUmsAutostart != mAutoStartUms) {
San Mehat1f6301e2010-01-07 22:40:27 -0800189 mAutoStartUms = newUmsAutostart;
190 }
191
192 boolean newUmsPrompt = (Settings.Secure.getInt(
193 cr, Settings.Secure.MOUNT_UMS_PROMPT, 1) == 1);
194
195 if (newUmsPrompt != mPromptUms) {
San Mehat1f6301e2010-01-07 22:40:27 -0800196 mPromptUms = newUmsAutostart;
197 }
198
199 boolean newUmsNotifyEnabled = (Settings.Secure.getInt(
200 cr, Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED, 1) == 1);
201
San Mehat1f6301e2010-01-07 22:40:27 -0800202 if (mUmsEnabled) {
203 if (newUmsNotifyEnabled) {
204 Intent intent = new Intent();
205 intent.setClass(mContext, com.android.internal.app.UsbStorageStopActivity.class);
206 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
207 setUsbStorageNotification(com.android.internal.R.string.usb_storage_stop_notification_title,
208 com.android.internal.R.string.usb_storage_stop_notification_message,
209 com.android.internal.R.drawable.stat_sys_warning,
210 false, true, pi);
211 } else {
212 setUsbStorageNotification(0, 0, 0, false, false, null);
213 }
214 }
215 if (newUmsNotifyEnabled != mUmsActiveNotify) {
San Mehat1f6301e2010-01-07 22:40:27 -0800216 mUmsActiveNotify = newUmsNotifyEnabled;
217 }
218 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 }
220
221 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
222 public void onReceive(Context context, Intent intent) {
San Mehat91c77612010-01-07 10:39:41 -0800223 String action = intent.getAction();
224
225 if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
San Mehat22dd86e2010-01-12 12:21:18 -0800226 /*
227 * Vold does not run in the simulator, so fake out a mounted
228 * event to trigger MediaScanner
229 */
230 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
231 notifyMediaMounted(
232 Environment.getExternalStorageDirectory().getPath(), false);
233 return;
234 }
235
236 Thread thread = new Thread(
237 mConnector, NativeDaemonConnector.class.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 thread.start();
239 }
240 }
241 };
242
San Mehat91c77612010-01-07 10:39:41 -0800243 public void shutdown() {
244 if (mContext.checkCallingOrSelfPermission(
245 android.Manifest.permission.SHUTDOWN)
246 != PackageManager.PERMISSION_GRANTED) {
247 throw new SecurityException("Requires SHUTDOWN permission");
248 }
249
San Mehat7ebf0172010-01-12 07:57:42 -0800250 Log.d(TAG, "Shutting down");
San Mehat91c77612010-01-07 10:39:41 -0800251 String state = Environment.getExternalStorageState();
252
253 if (state.equals(Environment.MEDIA_SHARED)) {
254 /*
255 * If the media is currently shared, unshare it.
256 * XXX: This is still dangerous!. We should not
257 * be rebooting at *all* if UMS is enabled, since
258 * the UMS host could have dirty FAT cache entries
259 * yet to flush.
260 */
261 try {
262 setMassStorageEnabled(false);
263 } catch (Exception e) {
264 Log.e(TAG, "ums disable failed", e);
265 }
266 } else if (state.equals(Environment.MEDIA_CHECKING)) {
267 /*
268 * If the media is being checked, then we need to wait for
269 * it to complete before being able to proceed.
270 */
271 // XXX: @hackbod - Should we disable the ANR timer here?
272 int retries = 30;
273 while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
274 try {
275 Thread.sleep(1000);
276 } catch (InterruptedException iex) {
277 Log.e(TAG, "Interrupted while waiting for media", iex);
278 break;
279 }
280 state = Environment.getExternalStorageState();
281 }
282 if (retries == 0) {
283 Log.e(TAG, "Timed out waiting for media to check");
284 }
285 }
286
287 if (state.equals(Environment.MEDIA_MOUNTED)) {
288 /*
289 * If the media is mounted, then gracefully unmount it.
290 */
291 try {
292 String m = Environment.getExternalStorageDirectory().toString();
San Mehat22dd86e2010-01-12 12:21:18 -0800293 unmountVolume(m);
San Mehat7ebf0172010-01-12 07:57:42 -0800294
295 int retries = 12;
296 while (!state.equals(Environment.MEDIA_UNMOUNTED) && (retries-- >=0)) {
297 try {
298 Thread.sleep(1000);
299 } catch (InterruptedException iex) {
300 Log.e(TAG, "Interrupted while waiting for media", iex);
301 break;
302 }
303 state = Environment.getExternalStorageState();
304 }
305 if (retries == 0) {
306 Log.e(TAG, "Timed out waiting for media to unmount");
Jean-Baptiste Querufa101532010-01-12 11:53:42 -0800307 }
San Mehat91c77612010-01-07 10:39:41 -0800308 } catch (Exception e) {
309 Log.e(TAG, "external storage unmount failed", e);
310 }
311 }
312 }
313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 /**
315 * @return true if USB mass storage support is enabled.
316 */
San Mehat36972292010-01-06 11:06:32 -0800317 public boolean getMassStorageEnabled() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800318 return mUmsEnabled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 }
320
321 /**
322 * Enables or disables USB mass storage support.
323 *
324 * @param enable true to enable USB mass storage support
325 */
San Mehat36972292010-01-06 11:06:32 -0800326 public void setMassStorageEnabled(boolean enable) throws IllegalStateException {
San Mehat1f6301e2010-01-07 22:40:27 -0800327 if (mContext.checkCallingOrSelfPermission(
328 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
329 != PackageManager.PERMISSION_GRANTED) {
330 throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
331 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800332 try {
333 String vp = Environment.getExternalStorageDirectory().getPath();
334 String vs = getVolumeState(vp);
335
San Mehat5fbf4092010-01-15 10:13:59 -0800336 mUmsEnabling = enable;
San Mehat7fd0fee2009-12-17 07:12:23 -0800337 if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
San Mehat22dd86e2010-01-12 12:21:18 -0800338 unmountVolume(vp);
San Mehat5fbf4092010-01-15 10:13:59 -0800339 mUmsEnabling = false;
San Mehat1f6301e2010-01-07 22:40:27 -0800340 updateUsbMassStorageNotification(true, false);
San Mehat7fd0fee2009-12-17 07:12:23 -0800341 }
342
San Mehat22dd86e2010-01-12 12:21:18 -0800343 setShareMethodEnabled(vp, "ums", enable);
San Mehat7fd0fee2009-12-17 07:12:23 -0800344 mUmsEnabled = enable;
San Mehat5fbf4092010-01-15 10:13:59 -0800345 mUmsEnabling = false;
San Mehat7fd0fee2009-12-17 07:12:23 -0800346 if (!enable) {
San Mehat22dd86e2010-01-12 12:21:18 -0800347 mountVolume(vp);
San Mehat1f6301e2010-01-07 22:40:27 -0800348 if (mPromptUms) {
349 updateUsbMassStorageNotification(false, false);
350 } else {
351 updateUsbMassStorageNotification(true, false);
352 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800353 }
San Mehat36972292010-01-06 11:06:32 -0800354 } catch (IllegalStateException rex) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800355 Log.e(TAG, "Failed to set ums enable {" + enable + "}");
356 return;
357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 }
359
360 /**
361 * @return true if USB mass storage is connected.
362 */
San Mehat36972292010-01-06 11:06:32 -0800363 public boolean getMassStorageConnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800364 return mUmsConnected;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800366
367 /**
368 * @return state of the volume at the specified mount point
369 */
San Mehat36972292010-01-06 11:06:32 -0800370 public String getVolumeState(String mountPoint) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800371 /*
372 * XXX: Until we have multiple volume discovery, just hardwire
373 * this to /sdcard
374 */
375 if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
376 Log.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
377 throw new IllegalArgumentException();
378 }
379
380 return mLegacyState;
381 }
382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383
384 /**
385 * Attempt to mount external media
386 */
San Mehat22dd86e2010-01-12 12:21:18 -0800387 public void mountVolume(String mountPath) throws IllegalStateException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 if (mContext.checkCallingOrSelfPermission(
389 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
390 != PackageManager.PERMISSION_GRANTED) {
391 throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
392 }
San Mehat22dd86e2010-01-12 12:21:18 -0800393 mConnector.doCommand(String.format("mount %s", mountPath));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 }
395
396 /**
397 * Attempt to unmount external media to prepare for eject
398 */
San Mehat22dd86e2010-01-12 12:21:18 -0800399 public void unmountVolume(String mountPath) throws IllegalStateException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 if (mContext.checkCallingOrSelfPermission(
401 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
402 != PackageManager.PERMISSION_GRANTED) {
403 throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
404 }
405
406 // Set a flag so that when we get the unmounted event, we know
407 // to display the notification
408 mShowSafeUnmountNotificationWhenUnmounted = true;
409
San Mehat22dd86e2010-01-12 12:21:18 -0800410 mConnector.doCommand(String.format("unmount %s", mountPath));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 }
412
413 /**
414 * Attempt to format external media
415 */
San Mehat22dd86e2010-01-12 12:21:18 -0800416 public void formatVolume(String formatPath) throws IllegalStateException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 if (mContext.checkCallingOrSelfPermission(
418 android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
419 != PackageManager.PERMISSION_GRANTED) {
420 throw new SecurityException("Requires MOUNT_FORMAT_FILESYSTEMS permission");
421 }
422
San Mehat22dd86e2010-01-12 12:21:18 -0800423 mConnector.doCommand(String.format("format %s", formatPath));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 }
425
San Mehat22dd86e2010-01-12 12:21:18 -0800426 boolean getShareAvailable(String method) throws IllegalStateException {
427 ArrayList<String> rsp = mConnector.doCommand("share_available " + method);
428
429 for (String line : rsp) {
430 String []tok = line.split(" ");
431 int code = Integer.parseInt(tok[0]);
432 if (code == VoldResponseCode.ShareAvailabilityResult) {
433 if (tok[2].equals("available"))
434 return true;
435 return false;
436 } else {
437 throw new IllegalStateException(String.format("Unexpected response code %d", code));
438 }
439 }
440 throw new IllegalStateException("Got an empty response");
441 }
442
443 /**
444 * Enables or disables USB mass storage support.
445 *
446 * @param enable true to enable USB mass storage support
447 */
448 void setShareMethodEnabled(String mountPoint, String method,
449 boolean enable) throws IllegalStateException {
450 mConnector.doCommand(String.format(
451 "%sshare %s %s", (enable ? "" : "un"), mountPoint, method));
452 }
453
454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 /**
456 * Returns true if we're playing media notification sounds.
457 */
458 public boolean getPlayNotificationSounds() {
459 return mPlaySounds;
460 }
461
462 /**
463 * Set whether or not we're playing media notification sounds.
464 */
465 public void setPlayNotificationSounds(boolean enabled) {
466 if (mContext.checkCallingOrSelfPermission(
467 android.Manifest.permission.WRITE_SETTINGS)
468 != PackageManager.PERMISSION_GRANTED) {
469 throw new SecurityException("Requires WRITE_SETTINGS permission");
470 }
471 mPlaySounds = enabled;
472 SystemProperties.set("persist.service.mount.playsnd", (enabled ? "1" : "0"));
473 }
474
San Mehat7fd0fee2009-12-17 07:12:23 -0800475 void updatePublicVolumeState(String mountPoint, String state) {
476 if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
477 Log.w(TAG, "Multiple volumes not currently supported");
478 return;
479 }
San Mehat22dd86e2010-01-12 12:21:18 -0800480 Log.i(TAG, "State for {" + mountPoint + "} = {" + state + "}");
San Mehat7fd0fee2009-12-17 07:12:23 -0800481 mLegacyState = state;
482 }
483
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700484 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 * Update the state of the USB mass storage notification
486 */
487 void updateUsbMassStorageNotification(boolean suppressIfConnected, boolean sound) {
488
489 try {
490
491 if (getMassStorageConnected() && !suppressIfConnected) {
492 Intent intent = new Intent();
493 intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
Mike Lockwood95174432009-08-26 09:44:09 -0700494 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
496 setUsbStorageNotification(
497 com.android.internal.R.string.usb_storage_notification_title,
498 com.android.internal.R.string.usb_storage_notification_message,
499 com.android.internal.R.drawable.stat_sys_data_usb,
500 sound, true, pi);
501 } else {
502 setUsbStorageNotification(0, 0, 0, false, false, null);
503 }
San Mehat36972292010-01-06 11:06:32 -0800504 } catch (IllegalStateException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 // Nothing to do
506 }
507 }
508
509 void handlePossibleExplicitUnmountBroadcast(String path) {
510 if (mMounted) {
511 mMounted = false;
512 Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED,
513 Uri.parse("file://" + path));
514 mContext.sendBroadcast(intent);
515 }
516 }
517
San Mehat22dd86e2010-01-12 12:21:18 -0800518 /**
519 *
520 * Callback from NativeDaemonConnector
521 */
522 public void onDaemonConnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800523 new Thread() {
524 public void run() {
525 try {
526 if (!getVolumeState(Environment.getExternalStorageDirectory().getPath())
527 .equals(Environment.MEDIA_MOUNTED)) {
528 try {
San Mehat22dd86e2010-01-12 12:21:18 -0800529 mountVolume(Environment.getExternalStorageDirectory().getPath());
San Mehat7fd0fee2009-12-17 07:12:23 -0800530 } catch (Exception ex) {
531 Log.w(TAG, "Connection-mount failed");
532 }
533 } else {
534 Log.d(TAG, "Skipping connection-mount; already mounted");
535 }
San Mehat36972292010-01-06 11:06:32 -0800536 } catch (IllegalStateException rex) {
San Mehat1f6301e2010-01-07 22:40:27 -0800537 Log.e(TAG, "Exception while handling connection mount ", rex);
San Mehat7fd0fee2009-12-17 07:12:23 -0800538 }
539
540 try {
San Mehat22dd86e2010-01-12 12:21:18 -0800541 boolean avail = getShareAvailable("ums");
San Mehat7fd0fee2009-12-17 07:12:23 -0800542 notifyShareAvailabilityChange("ums", avail);
543 } catch (Exception ex) {
544 Log.w(TAG, "Failed to get share availability");
545 }
546 }
547 }.start();
548 }
549
San Mehat22dd86e2010-01-12 12:21:18 -0800550 /**
551 *
552 * Callback from NativeDaemonConnector
553 */
554 public boolean onEvent(int code, String raw, String[] cooked) {
555 // Log.d(TAG, "event {" + raw + "}");
556 if (code == VoldResponseCode.VolumeStateChange) {
557 // FMT: NNN Volume <label> <mountpoint> state changed
558 // from <old_#> (<old_str>) to <new_#> (<new_str>)
559 notifyVolumeStateChange(
560 cooked[2], cooked[3], Integer.parseInt(cooked[7]),
561 Integer.parseInt(cooked[10]));
562 } else if (code == VoldResponseCode.VolumeMountFailedBlank) {
563 // FMT: NNN Volume <label> <mountpoint> mount failed - no supported file-systems
564 notifyMediaNoFs(cooked[3]);
565 // FMT: NNN Volume <label> <mountpoint> mount failed - no media
566 } else if (code == VoldResponseCode.VolumeMountFailedNoMedia) {
567 notifyMediaRemoved(cooked[3]);
568 } else if (code == VoldResponseCode.VolumeMountFailedDamaged) {
569 // FMT: NNN Volume <label> <mountpoint> mount failed - filesystem check failed
570 notifyMediaUnmountable(cooked[3]);
571 } else if (code == VoldResponseCode.ShareAvailabilityChange) {
572 // FMT: NNN Share method <method> now <available|unavailable>
573 boolean avail = false;
574 if (cooked[5].equals("available")) {
575 avail = true;
576 }
577 notifyShareAvailabilityChange(cooked[3], avail);
578 } else if (code == VoldResponseCode.VolumeDiskInserted) {
579 // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
580 notifyMediaInserted(cooked[3]);
581 } else if (code == VoldResponseCode.VolumeDiskRemoved) {
582 // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
583 notifyMediaRemoved(cooked[3]);
584 } else if (code == VoldResponseCode.VolumeBadRemoval) {
585 // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
586 notifyMediaBadRemoval(cooked[3]);
587 } else {
588 return false;
589 }
590 return true;
591 }
592
San Mehat7fd0fee2009-12-17 07:12:23 -0800593 void notifyVolumeStateChange(String label, String mountPoint, int oldState,
San Mehat36972292010-01-06 11:06:32 -0800594 int newState) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800595 String vs = getVolumeState(mountPoint);
596
597 if (newState == VolumeState.Init) {
598 } else if (newState == VolumeState.NoMedia) {
599 // NoMedia is handled via Disk Remove events
600 } else if (newState == VolumeState.Idle) {
San Mehat5fbf4092010-01-15 10:13:59 -0800601 /*
602 * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
603 * if we're in the process of enabling UMS
604 */
San Mehat7fd0fee2009-12-17 07:12:23 -0800605 if (!vs.equals(Environment.MEDIA_BAD_REMOVAL) &&
606 !vs.equals(Environment.MEDIA_NOFS) &&
San Mehat5fbf4092010-01-15 10:13:59 -0800607 !vs.equals(Environment.MEDIA_UNMOUNTABLE) &&
608 !mUmsEnabling) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800609 notifyMediaUnmounted(mountPoint);
610 }
611 } else if (newState == VolumeState.Pending) {
612 } else if (newState == VolumeState.Checking) {
613 notifyMediaChecking(mountPoint);
614 } else if (newState == VolumeState.Mounted) {
615 notifyMediaMounted(mountPoint, false);
616 } else if (newState == VolumeState.Unmounting) {
617 notifyMediaUnmounting(mountPoint);
618 } else if (newState == VolumeState.Formatting) {
619 } else if (newState == VolumeState.Shared) {
620 notifyMediaShared(mountPoint, false);
621 } else if (newState == VolumeState.SharedMnt) {
622 notifyMediaShared(mountPoint, true);
623 } else {
624 Log.e(TAG, "Unhandled VolumeState {" + newState + "}");
625 }
626 }
627
628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 /**
630 * Broadcasts the USB mass storage connected event to all clients.
631 */
632 void notifyUmsConnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800633 mUmsConnected = true;
634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 String storageState = Environment.getExternalStorageState();
636 if (!storageState.equals(Environment.MEDIA_REMOVED) &&
637 !storageState.equals(Environment.MEDIA_BAD_REMOVAL) &&
638 !storageState.equals(Environment.MEDIA_CHECKING)) {
639
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700640 if (mAutoStartUms) {
641 try {
642 setMassStorageEnabled(true);
San Mehat36972292010-01-06 11:06:32 -0800643 } catch (IllegalStateException e) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700644 }
San Mehat1f6301e2010-01-07 22:40:27 -0800645 } else if (mPromptUms) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700646 updateUsbMassStorageNotification(false, true);
647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 }
649
650 Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);
651 mContext.sendBroadcast(intent);
652 }
653
San Mehat1f6301e2010-01-07 22:40:27 -0800654 void notifyShareAvailabilityChange(String method, final boolean avail) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800655 if (!method.equals("ums")) {
656 Log.w(TAG, "Ignoring unsupported share method {" + method + "}");
657 return;
658 }
San Mehat1f6301e2010-01-07 22:40:27 -0800659
660 /*
661 * Notification needs to run in a different thread as
662 * it may need to call back into vold
663 */
664 new Thread() {
665 public void run() {
666 try {
667 if (avail) {
668 notifyUmsConnected();
669 } else {
670 notifyUmsDisconnected();
671 }
672 } catch (Exception ex) {
673 Log.w(TAG, "Failed to mount media on insertion");
674 }
675 }
676 }.start();
San Mehat7fd0fee2009-12-17 07:12:23 -0800677 }
678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 /**
680 * Broadcasts the USB mass storage disconnected event to all clients.
681 */
682 void notifyUmsDisconnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800683 mUmsConnected = false;
San Mehat1f6301e2010-01-07 22:40:27 -0800684 if (mUmsEnabled) {
685 try {
686 Log.w(TAG, "UMS disconnected while enabled!");
687 setMassStorageEnabled(false);
688 } catch (Exception ex) {
689 Log.e(TAG, "Error disabling UMS on unsafe UMS disconnect", ex);
690 }
691 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 updateUsbMassStorageNotification(false, false);
693 Intent intent = new Intent(Intent.ACTION_UMS_DISCONNECTED);
694 mContext.sendBroadcast(intent);
695 }
696
San Mehat36972292010-01-06 11:06:32 -0800697 void notifyMediaInserted(final String path) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800698 new Thread() {
699 public void run() {
700 try {
San Mehat22dd86e2010-01-12 12:21:18 -0800701 mountVolume(path);
San Mehat7fd0fee2009-12-17 07:12:23 -0800702 } catch (Exception ex) {
San Mehat1f6301e2010-01-07 22:40:27 -0800703 Log.w(TAG, "Failed to mount media on insertion", ex);
San Mehat7fd0fee2009-12-17 07:12:23 -0800704 }
705 }
706 }.start();
707 }
708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 /**
710 * Broadcasts the media removed event to all clients.
711 */
San Mehat36972292010-01-06 11:06:32 -0800712 void notifyMediaRemoved(String path) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800713
714 // Suppress this on bad removal
715 if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
716 return;
717 }
718
719 updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 updateUsbMassStorageNotification(true, false);
722
723 setMediaStorageNotification(
San Mehat7fd0fee2009-12-17 07:12:23 -0800724 com.android.internal.R.string.ext_media_nomedia_notification_title,
725 com.android.internal.R.string.ext_media_nomedia_notification_message,
726 com.android.internal.R.drawable.stat_notify_sdcard_usb,
727 true, false, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 handlePossibleExplicitUnmountBroadcast(path);
729
730 Intent intent = new Intent(Intent.ACTION_MEDIA_REMOVED,
731 Uri.parse("file://" + path));
732 mContext.sendBroadcast(intent);
733 }
734
735 /**
736 * Broadcasts the media unmounted event to all clients.
737 */
738 void notifyMediaUnmounted(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800739
740 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 if (mShowSafeUnmountNotificationWhenUnmounted) {
743 setMediaStorageNotification(
744 com.android.internal.R.string.ext_media_safe_unmount_notification_title,
745 com.android.internal.R.string.ext_media_safe_unmount_notification_message,
Mike Lockwoodde46acd2009-09-30 19:30:56 -0400746 com.android.internal.R.drawable.stat_notify_sdcard,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 true, true, null);
748 mShowSafeUnmountNotificationWhenUnmounted = false;
749 } else {
750 setMediaStorageNotification(0, 0, 0, false, false, null);
751 }
752 updateUsbMassStorageNotification(false, false);
753
754 Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED,
755 Uri.parse("file://" + path));
756 mContext.sendBroadcast(intent);
757 }
758
759 /**
760 * Broadcasts the media checking event to all clients.
761 */
762 void notifyMediaChecking(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800763 updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 setMediaStorageNotification(
766 com.android.internal.R.string.ext_media_checking_notification_title,
767 com.android.internal.R.string.ext_media_checking_notification_message,
Mike Lockwoodde46acd2009-09-30 19:30:56 -0400768 com.android.internal.R.drawable.stat_notify_sdcard_prepare,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 true, false, null);
770
771 updateUsbMassStorageNotification(true, false);
772 Intent intent = new Intent(Intent.ACTION_MEDIA_CHECKING,
773 Uri.parse("file://" + path));
774 mContext.sendBroadcast(intent);
775 }
776
777 /**
778 * Broadcasts the media nofs event to all clients.
779 */
780 void notifyMediaNoFs(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800781 updatePublicVolumeState(path, Environment.MEDIA_NOFS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782
783 Intent intent = new Intent();
784 intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
785 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
786
787 setMediaStorageNotification(com.android.internal.R.string.ext_media_nofs_notification_title,
788 com.android.internal.R.string.ext_media_nofs_notification_message,
Mike Lockwooda7ef2692009-09-10 11:15:26 -0400789 com.android.internal.R.drawable.stat_notify_sdcard_usb,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790 true, false, pi);
791 updateUsbMassStorageNotification(false, false);
792 intent = new Intent(Intent.ACTION_MEDIA_NOFS,
793 Uri.parse("file://" + path));
794 mContext.sendBroadcast(intent);
795 }
796
797 /**
798 * Broadcasts the media mounted event to all clients.
799 */
800 void notifyMediaMounted(String path, boolean readOnly) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800801 updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
802
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 setMediaStorageNotification(0, 0, 0, false, false, null);
804 updateUsbMassStorageNotification(false, false);
805 Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED,
806 Uri.parse("file://" + path));
807 intent.putExtra("read-only", readOnly);
808 mMounted = true;
809 mContext.sendBroadcast(intent);
810 }
811
812 /**
813 * Broadcasts the media shared event to all clients.
814 */
San Mehat7fd0fee2009-12-17 07:12:23 -0800815 void notifyMediaShared(String path, boolean mounted) {
816 if (mounted) {
817 Log.e(TAG, "Live shared mounts not supported yet!");
818 return;
819 }
820
821 updatePublicVolumeState(path, Environment.MEDIA_SHARED);
822
San Mehat1f6301e2010-01-07 22:40:27 -0800823 if (mUmsActiveNotify) {
824 Intent intent = new Intent();
825 intent.setClass(mContext, com.android.internal.app.UsbStorageStopActivity.class);
826 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
827 setUsbStorageNotification(com.android.internal.R.string.usb_storage_stop_notification_title,
828 com.android.internal.R.string.usb_storage_stop_notification_message,
829 com.android.internal.R.drawable.stat_sys_warning,
830 false, true, pi);
831 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 handlePossibleExplicitUnmountBroadcast(path);
San Mehat1f6301e2010-01-07 22:40:27 -0800833 Intent intent = new Intent(Intent.ACTION_MEDIA_SHARED,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 Uri.parse("file://" + path));
835 mContext.sendBroadcast(intent);
836 }
837
838 /**
839 * Broadcasts the media bad removal event to all clients.
840 */
841 void notifyMediaBadRemoval(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800842 updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 updateUsbMassStorageNotification(true, false);
845 setMediaStorageNotification(com.android.internal.R.string.ext_media_badremoval_notification_title,
846 com.android.internal.R.string.ext_media_badremoval_notification_message,
847 com.android.internal.R.drawable.stat_sys_warning,
848 true, true, null);
849
850 handlePossibleExplicitUnmountBroadcast(path);
851 Intent intent = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL,
852 Uri.parse("file://" + path));
853 mContext.sendBroadcast(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 }
855
856 /**
857 * Broadcasts the media unmountable event to all clients.
858 */
859 void notifyMediaUnmountable(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800860 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
861
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 Intent intent = new Intent();
863 intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
864 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
865
866 setMediaStorageNotification(com.android.internal.R.string.ext_media_unmountable_notification_title,
867 com.android.internal.R.string.ext_media_unmountable_notification_message,
Mike Lockwooda7ef2692009-09-10 11:15:26 -0400868 com.android.internal.R.drawable.stat_notify_sdcard_usb,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 true, false, pi);
870 updateUsbMassStorageNotification(false, false);
871
872 handlePossibleExplicitUnmountBroadcast(path);
873
874 intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE,
875 Uri.parse("file://" + path));
876 mContext.sendBroadcast(intent);
877 }
878
879 /**
880 * Broadcasts the media eject event to all clients.
881 */
San Mehat7fd0fee2009-12-17 07:12:23 -0800882 void notifyMediaUnmounting(String path) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 Intent intent = new Intent(Intent.ACTION_MEDIA_EJECT,
884 Uri.parse("file://" + path));
885 mContext.sendBroadcast(intent);
886 }
887
888 /**
889 * Sets the USB storage notification.
890 */
891 private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon, boolean sound, boolean visible,
892 PendingIntent pi) {
893
894 if (!visible && mUsbStorageNotification == null) {
895 return;
896 }
897
898 NotificationManager notificationManager = (NotificationManager) mContext
899 .getSystemService(Context.NOTIFICATION_SERVICE);
900
901 if (notificationManager == null) {
902 return;
903 }
904
905 if (visible) {
906 Resources r = Resources.getSystem();
907 CharSequence title = r.getText(titleId);
908 CharSequence message = r.getText(messageId);
909
910 if (mUsbStorageNotification == null) {
911 mUsbStorageNotification = new Notification();
912 mUsbStorageNotification.icon = icon;
913 mUsbStorageNotification.when = 0;
914 }
915
916 if (sound && mPlaySounds) {
917 mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
918 } else {
919 mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
920 }
921
922 mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
923
924 mUsbStorageNotification.tickerText = title;
925 if (pi == null) {
926 Intent intent = new Intent();
927 pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
928 }
929
930 mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
931 }
932
933 final int notificationId = mUsbStorageNotification.icon;
934 if (visible) {
935 notificationManager.notify(notificationId, mUsbStorageNotification);
936 } else {
937 notificationManager.cancel(notificationId);
938 }
939 }
940
941 private synchronized boolean getMediaStorageNotificationDismissable() {
942 if ((mMediaStorageNotification != null) &&
943 ((mMediaStorageNotification.flags & Notification.FLAG_AUTO_CANCEL) ==
944 Notification.FLAG_AUTO_CANCEL))
945 return true;
946
947 return false;
948 }
949
950 /**
951 * Sets the media storage notification.
952 */
953 private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible,
954 boolean dismissable, PendingIntent pi) {
955
956 if (!visible && mMediaStorageNotification == null) {
957 return;
958 }
959
960 NotificationManager notificationManager = (NotificationManager) mContext
961 .getSystemService(Context.NOTIFICATION_SERVICE);
962
963 if (notificationManager == null) {
964 return;
965 }
966
967 if (mMediaStorageNotification != null && visible) {
968 /*
969 * Dismiss the previous notification - we're about to
970 * re-use it.
971 */
972 final int notificationId = mMediaStorageNotification.icon;
973 notificationManager.cancel(notificationId);
974 }
975
976 if (visible) {
977 Resources r = Resources.getSystem();
978 CharSequence title = r.getText(titleId);
979 CharSequence message = r.getText(messageId);
980
981 if (mMediaStorageNotification == null) {
982 mMediaStorageNotification = new Notification();
983 mMediaStorageNotification.when = 0;
984 }
985
986 if (mPlaySounds) {
987 mMediaStorageNotification.defaults |= Notification.DEFAULT_SOUND;
988 } else {
989 mMediaStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
990 }
991
992 if (dismissable) {
993 mMediaStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
994 } else {
995 mMediaStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
996 }
997
998 mMediaStorageNotification.tickerText = title;
999 if (pi == null) {
1000 Intent intent = new Intent();
1001 pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
1002 }
1003
1004 mMediaStorageNotification.icon = icon;
1005 mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
1006 }
1007
1008 final int notificationId = mMediaStorageNotification.icon;
1009 if (visible) {
1010 notificationManager.notify(notificationId, mMediaStorageNotification);
1011 } else {
1012 notificationManager.cancel(notificationId);
1013 }
1014 }
San Mehat36972292010-01-06 11:06:32 -08001015
San Mehat0f5525a2010-01-11 10:15:16 -08001016 public String[] getSecureContainerList() throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001017 ArrayList<String> rsp = mConnector.doCommand("list_asec");
1018
1019 String[] rdata = new String[rsp.size()];
1020 int idx = 0;
1021
1022 for (String line : rsp) {
1023 String []tok = line.split(" ");
1024 int code = Integer.parseInt(tok[0]);
1025 if (code == VoldResponseCode.AsecListResult) {
1026 rdata[idx++] = tok[1];
1027 } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
1028 return rdata;
1029 } else {
1030 throw new IllegalStateException(String.format("Unexpected response code %d", code));
1031 }
1032 }
1033 throw new IllegalStateException("Got an empty response");
San Mehat36972292010-01-06 11:06:32 -08001034 }
1035
San Mehat0f5525a2010-01-11 10:15:16 -08001036 public String createSecureContainer(String id, int sizeMb, String fstype,
San Mehat36972292010-01-06 11:06:32 -08001037 String key, int ownerUid) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001038 String cmd = String.format("create_asec %s %d %s %s %d",
1039 id, sizeMb, fstype, key, ownerUid);
1040 mConnector.doCommand(cmd);
1041 return getSecureContainerPath(id);
San Mehat36972292010-01-06 11:06:32 -08001042 }
1043
San Mehat0f5525a2010-01-11 10:15:16 -08001044 public void finalizeSecureContainer(String id) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001045 mConnector.doCommand(String.format("finalize_asec %s", id));
San Mehat36972292010-01-06 11:06:32 -08001046 }
1047
San Mehat0f5525a2010-01-11 10:15:16 -08001048 public void destroySecureContainer(String id) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001049 mConnector.doCommand(String.format("destroy_asec %s", id));
San Mehat36972292010-01-06 11:06:32 -08001050 }
1051
San Mehat22dd86e2010-01-12 12:21:18 -08001052 public String mountSecureContainer(String id, String key,
1053 int ownerUid) throws IllegalStateException {
1054 String cmd = String.format("mount_asec %s %s %d",
1055 id, key, ownerUid);
1056 mConnector.doCommand(cmd);
1057 return getSecureContainerPath(id);
San Mehat36972292010-01-06 11:06:32 -08001058 }
1059
San Mehat9dba7092010-01-18 06:47:41 -08001060 public void unmountSecureContainer(String id) throws IllegalStateException {
1061 String cmd = String.format("unmount_asec %s ", id);
1062 mConnector.doCommand(cmd);
1063 }
1064
San Mehat0f5525a2010-01-11 10:15:16 -08001065 public String getSecureContainerPath(String id) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001066 ArrayList<String> rsp = mConnector.doCommand("asec_path " + id);
San Mehat36972292010-01-06 11:06:32 -08001067
San Mehat22dd86e2010-01-12 12:21:18 -08001068 for (String line : rsp) {
1069 String []tok = line.split(" ");
1070 int code = Integer.parseInt(tok[0]);
1071 if (code == VoldResponseCode.AsecPathResult) {
1072 return tok[1];
1073 } else {
1074 throw new IllegalStateException(String.format("Unexpected response code %d", code));
1075 }
1076 }
1077 throw new IllegalStateException("Got an empty response");
1078 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079}
1080