StorageManager.java revision 02ca31fbae9f35dd30f79de6927fae11b549391a
1/* 2 * Copyright (C) 2008 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 android.os.storage; 18 19import android.os.Handler; 20import android.os.Looper; 21import android.os.Message; 22import android.os.RemoteException; 23import android.os.ServiceManager; 24import android.util.Log; 25 26import java.util.ArrayList; 27 28/** 29 * StorageManager is the interface to the systems storage service. 30 * Get an instance of this class by calling 31 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument 32 * of {@link android.content.Context#STORAGE_SERVICE}. 33 */ 34 35public class StorageManager 36{ 37 private static final String TAG = "StorageManager"; 38 39 /* 40 * Our internal MountService binder reference 41 */ 42 private IMountService mMountService; 43 44 /* 45 * The looper target for callbacks 46 */ 47 Looper mTgtLooper; 48 49 /* 50 * Target listener for binder callbacks 51 */ 52 private MountServiceBinderListener mBinderListener; 53 54 /* 55 * List of our listeners 56 */ 57 private ArrayList<ListenerDelegate> mListeners = new ArrayList<ListenerDelegate>(); 58 59 private class MountServiceBinderListener extends IMountServiceListener.Stub { 60 public void onUsbMassStorageConnectionChanged(boolean available) { 61 final int size = mListeners.size(); 62 for (int i = 0; i < size; i++) { 63 mListeners.get(i).sendShareAvailabilityChanged(available); 64 } 65 } 66 67 public void onStorageStateChanged(String path, String oldState, String newState) { 68 final int size = mListeners.size(); 69 for (int i = 0; i < size; i++) { 70 mListeners.get(i).sendStorageStateChanged(path, oldState, newState); 71 } 72 } 73 } 74 75 /** 76 * Binder listener for OBB action results. 77 */ 78 private final ObbActionBinderListener mObbActionListener = new ObbActionBinderListener(); 79 private class ObbActionBinderListener extends IObbActionListener.Stub { 80 @Override 81 public void onObbResult(String filename, String status) throws RemoteException { 82 Log.i(TAG, "filename = " + filename + ", result = " + status); 83 } 84 } 85 86 /** 87 * Private base class for messages sent between the callback thread 88 * and the target looper handler. 89 */ 90 private class StorageEvent { 91 public static final int EVENT_UMS_CONNECTION_CHANGED = 1; 92 public static final int EVENT_STORAGE_STATE_CHANGED = 2; 93 94 private Message mMessage; 95 96 public StorageEvent(int what) { 97 mMessage = Message.obtain(); 98 mMessage.what = what; 99 mMessage.obj = this; 100 } 101 102 public Message getMessage() { 103 return mMessage; 104 } 105 } 106 107 /** 108 * Message sent on a USB mass storage connection change. 109 */ 110 private class UmsConnectionChangedStorageEvent extends StorageEvent { 111 public boolean available; 112 113 public UmsConnectionChangedStorageEvent(boolean a) { 114 super(EVENT_UMS_CONNECTION_CHANGED); 115 available = a; 116 } 117 } 118 119 /** 120 * Message sent on volume state change. 121 */ 122 private class StorageStateChangedStorageEvent extends StorageEvent { 123 public String path; 124 public String oldState; 125 public String newState; 126 127 public StorageStateChangedStorageEvent(String p, String oldS, String newS) { 128 super(EVENT_STORAGE_STATE_CHANGED); 129 path = p; 130 oldState = oldS; 131 newState = newS; 132 } 133 } 134 135 /** 136 * Private class containing sender and receiver code for StorageEvents. 137 */ 138 private class ListenerDelegate { 139 final StorageEventListener mStorageEventListener; 140 private final Handler mHandler; 141 142 ListenerDelegate(StorageEventListener listener) { 143 mStorageEventListener = listener; 144 mHandler = new Handler(mTgtLooper) { 145 @Override 146 public void handleMessage(Message msg) { 147 StorageEvent e = (StorageEvent) msg.obj; 148 149 if (msg.what == StorageEvent.EVENT_UMS_CONNECTION_CHANGED) { 150 UmsConnectionChangedStorageEvent ev = (UmsConnectionChangedStorageEvent) e; 151 mStorageEventListener.onUsbMassStorageConnectionChanged(ev.available); 152 } else if (msg.what == StorageEvent.EVENT_STORAGE_STATE_CHANGED) { 153 StorageStateChangedStorageEvent ev = (StorageStateChangedStorageEvent) e; 154 mStorageEventListener.onStorageStateChanged(ev.path, ev.oldState, ev.newState); 155 } else { 156 Log.e(TAG, "Unsupported event " + msg.what); 157 } 158 } 159 }; 160 } 161 162 StorageEventListener getListener() { 163 return mStorageEventListener; 164 } 165 166 void sendShareAvailabilityChanged(boolean available) { 167 UmsConnectionChangedStorageEvent e = new UmsConnectionChangedStorageEvent(available); 168 mHandler.sendMessage(e.getMessage()); 169 } 170 171 void sendStorageStateChanged(String path, String oldState, String newState) { 172 StorageStateChangedStorageEvent e = new StorageStateChangedStorageEvent(path, oldState, newState); 173 mHandler.sendMessage(e.getMessage()); 174 } 175 } 176 177 /** 178 * Constructs a StorageManager object through which an application can 179 * can communicate with the systems mount service. 180 * 181 * @param tgtLooper The {@android.os.Looper} which events will be received on. 182 * 183 * <p>Applications can get instance of this class by calling 184 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument 185 * of {@link android.content.Context#STORAGE_SERVICE}. 186 * 187 * @hide 188 */ 189 public StorageManager(Looper tgtLooper) throws RemoteException { 190 mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount")); 191 if (mMountService == null) { 192 Log.e(TAG, "Unable to connect to mount service! - is it running yet?"); 193 return; 194 } 195 mTgtLooper = tgtLooper; 196 mBinderListener = new MountServiceBinderListener(); 197 mMountService.registerListener(mBinderListener); 198 } 199 200 201 /** 202 * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}. 203 * 204 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object. 205 * 206 * @hide 207 */ 208 public void registerListener(StorageEventListener listener) { 209 if (listener == null) { 210 return; 211 } 212 213 synchronized (mListeners) { 214 mListeners.add(new ListenerDelegate(listener)); 215 } 216 } 217 218 /** 219 * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}. 220 * 221 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object. 222 * 223 * @hide 224 */ 225 public void unregisterListener(StorageEventListener listener) { 226 if (listener == null) { 227 return; 228 } 229 230 synchronized (mListeners) { 231 final int size = mListeners.size(); 232 for (int i=0 ; i<size ; i++) { 233 ListenerDelegate l = mListeners.get(i); 234 if (l.getListener() == listener) { 235 mListeners.remove(i); 236 break; 237 } 238 } 239 } 240 } 241 242 /** 243 * Enables USB Mass Storage (UMS) on the device. 244 * 245 * @hide 246 */ 247 public void enableUsbMassStorage() { 248 try { 249 mMountService.setUsbMassStorageEnabled(true); 250 } catch (Exception ex) { 251 Log.e(TAG, "Failed to enable UMS", ex); 252 } 253 } 254 255 /** 256 * Disables USB Mass Storage (UMS) on the device. 257 * 258 * @hide 259 */ 260 public void disableUsbMassStorage() { 261 try { 262 mMountService.setUsbMassStorageEnabled(false); 263 } catch (Exception ex) { 264 Log.e(TAG, "Failed to disable UMS", ex); 265 } 266 } 267 268 /** 269 * Query if a USB Mass Storage (UMS) host is connected. 270 * @return true if UMS host is connected. 271 * 272 * @hide 273 */ 274 public boolean isUsbMassStorageConnected() { 275 try { 276 return mMountService.isUsbMassStorageConnected(); 277 } catch (Exception ex) { 278 Log.e(TAG, "Failed to get UMS connection state", ex); 279 } 280 return false; 281 } 282 283 /** 284 * Query if a USB Mass Storage (UMS) is enabled on the device. 285 * @return true if UMS host is enabled. 286 * 287 * @hide 288 */ 289 public boolean isUsbMassStorageEnabled() { 290 try { 291 return mMountService.isUsbMassStorageEnabled(); 292 } catch (RemoteException rex) { 293 Log.e(TAG, "Failed to get UMS enable state", rex); 294 } 295 return false; 296 } 297 298 /** 299 * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is 300 * specified, it is supplied to the mounting process to be used in any 301 * encryption used in the OBB. 302 * <p> 303 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the 304 * file matches a package ID that is owned by the calling program's UID. 305 * That is, shared UID applications can obtain access to any other 306 * application's OBB that shares its UID. 307 * <p> 308 * STOPSHIP document more; discuss lack of guarantees of security 309 * 310 * @param filename the path to the OBB file 311 * @param key decryption key 312 * @return whether the mount call was successfully queued or not 313 */ 314 public boolean mountObb(String filename, String key) { 315 try { 316 mMountService.mountObb(filename, key, mObbActionListener); 317 return true; 318 } catch (RemoteException e) { 319 Log.e(TAG, "Failed to mount OBB", e); 320 } 321 322 return false; 323 } 324 325 /** 326 * Unmount an Opaque Binary Blob (OBB) file. If the <code>force</code> flag 327 * is true, it will kill any application needed to unmount the given OBB. 328 * <p> 329 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the 330 * file matches a package ID that is owned by the calling program's UID. 331 * That is, shared UID applications can obtain access to any other 332 * application's OBB that shares its UID. 333 * <p> 334 * STOPSHIP document more; discuss lack of guarantees of security 335 * 336 * @param filename path to the OBB file 337 * @param force whether to kill any programs using this in order to unmount 338 * it 339 * @return whether the unmount call was successfully queued or not 340 * @throws IllegalArgumentException when OBB is not already mounted 341 */ 342 public boolean unmountObb(String filename, boolean force) throws IllegalArgumentException { 343 try { 344 mMountService.unmountObb(filename, force, mObbActionListener); 345 return true; 346 } catch (RemoteException e) { 347 Log.e(TAG, "Failed to mount OBB", e); 348 } 349 350 return false; 351 } 352 353 /** 354 * Check whether an Opaque Binary Blob (OBB) is mounted or not. 355 * 356 * @param filename path to OBB image 357 * @return true if OBB is mounted; false if not mounted or on error 358 */ 359 public boolean isObbMounted(String filename) throws IllegalArgumentException { 360 try { 361 return mMountService.isObbMounted(filename); 362 } catch (RemoteException e) { 363 Log.e(TAG, "Failed to check if OBB is mounted", e); 364 } 365 366 return false; 367 } 368 369 /** 370 * Check the mounted path of an Opaque Binary Blob (OBB) file. This will 371 * give you the path to where you can obtain access to the internals of the 372 * OBB. 373 * 374 * @param filename path to OBB image 375 * @return absolute path to mounted OBB image data or <code>null</code> if 376 * not mounted or exception encountered trying to read status 377 */ 378 public String getMountedObbPath(String filename) { 379 try { 380 return mMountService.getMountedObbPath(filename); 381 } catch (RemoteException e) { 382 Log.e(TAG, "Failed to find mounted path for OBB", e); 383 } catch (IllegalArgumentException e) { 384 Log.d(TAG, "Couldn't read OBB file", e); 385 } 386 387 return null; 388 } 389} 390