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