• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 
17 package com.android.providers.media;
18 
19 import android.app.KeyguardManager;
20 import android.app.Service;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.hardware.usb.UsbManager;
26 import android.mtp.MtpDatabase;
27 import android.mtp.MtpServer;
28 import android.mtp.MtpStorage;
29 import android.os.Environment;
30 import android.os.Handler;
31 import android.os.IBinder;
32 import android.os.storage.StorageEventListener;
33 import android.os.storage.StorageManager;
34 import android.os.storage.StorageVolume;
35 import android.provider.Settings;
36 import android.util.Log;
37 
38 import java.io.File;
39 import java.util.HashMap;
40 
41 public class MtpService extends Service {
42     private static final String TAG = "MtpService";
43 
44     // We restrict PTP to these subdirectories
45     private static final String[] PTP_DIRECTORIES = new String[] {
46         Environment.DIRECTORY_DCIM,
47         Environment.DIRECTORY_PICTURES,
48     };
49 
addStorageDevicesLocked()50     private void addStorageDevicesLocked() {
51         if (mPtpMode) {
52             // In PTP mode we support only primary storage
53             addStorageLocked(mVolumeMap.get(mVolumes[0].getPath()));
54         } else {
55             for (StorageVolume volume : mVolumeMap.values()) {
56                 addStorageLocked(volume);
57             }
58         }
59     }
60 
61     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
62         @Override
63         public void onReceive(Context context, Intent intent) {
64             final String action = intent.getAction();
65             if (Intent.ACTION_USER_PRESENT.equals(action)) {
66                 synchronized (mBinder) {
67                     // Unhide the storage units when the user has unlocked the lockscreen
68                     if (mMtpDisabled) {
69                         addStorageDevicesLocked();
70                         mMtpDisabled = false;
71                     }
72                 }
73             }
74         }
75     };
76 
77     private final StorageEventListener mStorageEventListener = new StorageEventListener() {
78         public void onStorageStateChanged(String path, String oldState, String newState) {
79             synchronized (mBinder) {
80                 Log.d(TAG, "onStorageStateChanged " + path + " " + oldState + " -> " + newState);
81                 if (Environment.MEDIA_MOUNTED.equals(newState)) {
82                     volumeMountedLocked(path);
83                 } else if (Environment.MEDIA_MOUNTED.equals(oldState)) {
84                     StorageVolume volume = mVolumeMap.remove(path);
85                     if (volume != null) {
86                         removeStorageLocked(volume);
87                     }
88                 }
89             }
90         }
91     };
92 
93     private MtpDatabase mDatabase;
94     private MtpServer mServer;
95     private StorageManager mStorageManager;
96     private boolean mMtpDisabled; // true if MTP is disabled due to secure keyguard
97     private boolean mPtpMode;
98     private final HashMap<String, StorageVolume> mVolumeMap = new HashMap<String, StorageVolume>();
99     private final HashMap<String, MtpStorage> mStorageMap = new HashMap<String, MtpStorage>();
100     private StorageVolume[] mVolumes;
101 
102     @Override
onCreate()103     public void onCreate() {
104         // lock MTP if the keyguard is locked and secure
105         KeyguardManager keyguardManager =
106                 (KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE);
107         mMtpDisabled = keyguardManager.isKeyguardLocked() && keyguardManager.isKeyguardSecure();
108         registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_PRESENT));
109 
110         mStorageManager = (StorageManager)getSystemService(Context.STORAGE_SERVICE);
111         synchronized (mBinder) {
112             mStorageManager.registerListener(mStorageEventListener);
113             StorageVolume[] volumes = mStorageManager.getVolumeList();
114             mVolumes = volumes;
115             for (int i = 0; i < volumes.length; i++) {
116                 String path = volumes[i].getPath();
117                 String state = mStorageManager.getVolumeState(path);
118                 if (Environment.MEDIA_MOUNTED.equals(state)) {
119                    volumeMountedLocked(path);
120                 }
121             }
122         }
123     }
124 
125     @Override
onStartCommand(Intent intent, int flags, int startId)126     public int onStartCommand(Intent intent, int flags, int startId) {
127         synchronized (mBinder) {
128             if (mServer == null) {
129                 mPtpMode = (intent == null ? false
130                         : intent.getBooleanExtra(UsbManager.USB_FUNCTION_PTP, false));
131                 Log.d(TAG, "starting MTP server in " + (mPtpMode ? "PTP mode" : "MTP mode"));
132                 String[] subdirs = null;
133                 if (mPtpMode) {
134                     int count = PTP_DIRECTORIES.length;
135                     subdirs = new String[count];
136                     for (int i = 0; i < count; i++) {
137                         File file =
138                                 Environment.getExternalStoragePublicDirectory(PTP_DIRECTORIES[i]);
139                         // make sure this directory exists
140                         file.mkdirs();
141                         subdirs[i] = file.getPath();
142                     }
143                 }
144                 mDatabase = new MtpDatabase(this, MediaProvider.EXTERNAL_VOLUME,
145                         mVolumes[0].getPath(), subdirs);
146                 mServer = new MtpServer(mDatabase, mPtpMode);
147                 if (!mMtpDisabled) {
148                     addStorageDevicesLocked();
149                 }
150                 mServer.start();
151             }
152         }
153 
154         return START_STICKY;
155     }
156 
157     @Override
onDestroy()158     public void onDestroy()
159     {
160         unregisterReceiver(mReceiver);
161         mStorageManager.unregisterListener(mStorageEventListener);
162     }
163 
164     private final IMtpService.Stub mBinder =
165             new IMtpService.Stub() {
166         public void sendObjectAdded(int objectHandle) {
167             synchronized (mBinder) {
168                 if (mServer != null) {
169                     mServer.sendObjectAdded(objectHandle);
170                 }
171             }
172         }
173 
174         public void sendObjectRemoved(int objectHandle) {
175             synchronized (mBinder) {
176                 if (mServer != null) {
177                     mServer.sendObjectRemoved(objectHandle);
178                 }
179             }
180         }
181     };
182 
183     @Override
onBind(Intent intent)184     public IBinder onBind(Intent intent)
185     {
186         return mBinder;
187     }
188 
volumeMountedLocked(String path)189     private void volumeMountedLocked(String path) {
190         for (int i = 0; i < mVolumes.length; i++) {
191             StorageVolume volume = mVolumes[i];
192             if (volume.getPath().equals(path)) {
193                 mVolumeMap.put(path, volume);
194                 if (!mMtpDisabled) {
195                     // In PTP mode we support only primary storage
196                     if (i == 0 || !mPtpMode) {
197                         addStorageLocked(volume);
198                     }
199                 }
200                 break;
201             }
202         }
203     }
204 
addStorageLocked(StorageVolume volume)205     private void addStorageLocked(StorageVolume volume) {
206         MtpStorage storage = new MtpStorage(volume, getApplicationContext());
207         String path = storage.getPath();
208         mStorageMap.put(path, storage);
209 
210         Log.d(TAG, "addStorageLocked " + storage.getStorageId() + " " +path);
211         if (mDatabase != null) {
212             mDatabase.addStorage(storage);
213         }
214         if (mServer != null) {
215             mServer.addStorage(storage);
216         }
217     }
218 
removeStorageLocked(StorageVolume volume)219     private void removeStorageLocked(StorageVolume volume) {
220         MtpStorage storage = mStorageMap.remove(volume.getPath());
221         if (storage == null) {
222             Log.e(TAG, "no MtpStorage for " + volume.getPath());
223             return;
224         }
225 
226         Log.d(TAG, "removeStorageLocked " + storage.getStorageId() + " " + storage.getPath());
227         if (mDatabase != null) {
228             mDatabase.removeStorage(storage);
229         }
230         if (mServer != null) {
231             mServer.removeStorage(storage);
232         }
233     }
234 }
235 
236