UsbService.java revision 2a67840c3c35a6267663e5d3ae921ee9ac614db9
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 an
14 * limitations under the License.
15 */
16
17package com.android.server.usb;
18
19import android.app.PendingIntent;
20import android.app.admin.DevicePolicyManager;
21import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.content.pm.PackageManager;
26import android.hardware.usb.IUsbManager;
27import android.hardware.usb.UsbAccessory;
28import android.hardware.usb.UsbDevice;
29import android.hardware.usb.UsbManager;
30import android.os.Bundle;
31import android.os.ParcelFileDescriptor;
32import android.os.UserHandle;
33import android.os.UserManager;
34import android.util.Slog;
35import android.util.SparseArray;
36
37import com.android.internal.annotations.GuardedBy;
38import com.android.internal.util.IndentingPrintWriter;
39import com.android.server.SystemService;
40
41import java.io.File;
42import java.io.FileDescriptor;
43import java.io.PrintWriter;
44
45/**
46 * UsbService manages all USB related state, including both host and device support.
47 * Host related events and calls are delegated to UsbHostManager, and device related
48 * support is delegated to UsbDeviceManager.
49 */
50public class UsbService extends IUsbManager.Stub {
51
52    public static class Lifecycle extends SystemService {
53        private UsbService mUsbService;
54
55        public Lifecycle(Context context) {
56            super(context);
57        }
58
59        @Override
60        public void onStart() {
61            mUsbService = new UsbService(getContext());
62            publishBinderService(Context.USB_SERVICE, mUsbService);
63        }
64
65        @Override
66        public void onBootPhase(int phase) {
67            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
68                mUsbService.systemReady();
69            } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
70                mUsbService.bootCompleted();
71            }
72        }
73    }
74
75    private static final String TAG = "UsbService";
76
77    private final Context mContext;
78
79    private UsbDeviceManager mDeviceManager;
80    private UsbHostManager mHostManager;
81    private final UsbAlsaManager mAlsaManager;
82
83    private final Object mLock = new Object();
84
85    /** Map from {@link UserHandle} to {@link UsbSettingsManager} */
86    @GuardedBy("mLock")
87    private final SparseArray<UsbSettingsManager>
88            mSettingsByUser = new SparseArray<UsbSettingsManager>();
89
90    private UsbSettingsManager getSettingsForUser(int userId) {
91        synchronized (mLock) {
92            UsbSettingsManager settings = mSettingsByUser.get(userId);
93            if (settings == null) {
94                settings = new UsbSettingsManager(mContext, new UserHandle(userId));
95                mSettingsByUser.put(userId, settings);
96            }
97            return settings;
98        }
99    }
100
101    public UsbService(Context context) {
102        mContext = context;
103
104        mAlsaManager = new UsbAlsaManager(context);
105
106        final PackageManager pm = mContext.getPackageManager();
107        if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
108            mHostManager = new UsbHostManager(context, mAlsaManager);
109        }
110        if (new File("/sys/class/android_usb").exists()) {
111            mDeviceManager = new UsbDeviceManager(context, mAlsaManager);
112        }
113
114        setCurrentUser(UserHandle.USER_OWNER);
115
116        final IntentFilter filter = new IntentFilter();
117        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
118        filter.addAction(Intent.ACTION_USER_SWITCHED);
119        filter.addAction(Intent.ACTION_USER_STOPPED);
120        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
121        mContext.registerReceiver(mReceiver, filter, null, null);
122    }
123
124    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
125        @Override
126        public void onReceive(Context context, Intent intent) {
127            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
128            final String action = intent.getAction();
129            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
130                setCurrentUser(userId);
131            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
132                synchronized (mLock) {
133                    mSettingsByUser.remove(userId);
134                }
135            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
136                    .equals(action)) {
137                if (mDeviceManager != null) {
138                    mDeviceManager.updateUserRestrictions();
139                }
140            }
141        }
142    };
143
144    private void setCurrentUser(int userId) {
145        final UsbSettingsManager userSettings = getSettingsForUser(userId);
146        if (mHostManager != null) {
147            mHostManager.setCurrentSettings(userSettings);
148        }
149        if (mDeviceManager != null) {
150            mDeviceManager.setCurrentUser(userId, userSettings);
151        }
152    }
153
154    public void systemReady() {
155        mAlsaManager.systemReady();
156
157        if (mDeviceManager != null) {
158            mDeviceManager.systemReady();
159        }
160        if (mHostManager != null) {
161            mHostManager.systemReady();
162        }
163    }
164
165    public void bootCompleted() {
166        if (mDeviceManager != null) {
167            mDeviceManager.bootCompleted();
168        }
169    }
170
171    /* Returns a list of all currently attached USB devices (host mdoe) */
172    @Override
173    public void getDeviceList(Bundle devices) {
174        if (mHostManager != null) {
175            mHostManager.getDeviceList(devices);
176        }
177    }
178
179    /* Opens the specified USB device (host mode) */
180    @Override
181    public ParcelFileDescriptor openDevice(String deviceName) {
182        if (mHostManager != null) {
183            return mHostManager.openDevice(deviceName);
184        } else {
185            return null;
186        }
187    }
188
189    /* returns the currently attached USB accessory (device mode) */
190    @Override
191    public UsbAccessory getCurrentAccessory() {
192        if (mDeviceManager != null) {
193            return mDeviceManager.getCurrentAccessory();
194        } else {
195            return null;
196        }
197    }
198
199    /* opens the currently attached USB accessory (device mode) */
200    @Override
201    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
202        if (mDeviceManager != null) {
203            return mDeviceManager.openAccessory(accessory);
204        } else {
205            return null;
206        }
207    }
208
209    @Override
210    public void setDevicePackage(UsbDevice device, String packageName, int userId) {
211        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
212        getSettingsForUser(userId).setDevicePackage(device, packageName);
213    }
214
215    @Override
216    public void setAccessoryPackage(UsbAccessory accessory, String packageName, int userId) {
217        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
218        getSettingsForUser(userId).setAccessoryPackage(accessory, packageName);
219    }
220
221    @Override
222    public boolean hasDevicePermission(UsbDevice device) {
223        final int userId = UserHandle.getCallingUserId();
224        return getSettingsForUser(userId).hasPermission(device);
225    }
226
227    @Override
228    public boolean hasAccessoryPermission(UsbAccessory accessory) {
229        final int userId = UserHandle.getCallingUserId();
230        return getSettingsForUser(userId).hasPermission(accessory);
231    }
232
233    @Override
234    public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) {
235        final int userId = UserHandle.getCallingUserId();
236        getSettingsForUser(userId).requestPermission(device, packageName, pi);
237    }
238
239    @Override
240    public void requestAccessoryPermission(
241            UsbAccessory accessory, String packageName, PendingIntent pi) {
242        final int userId = UserHandle.getCallingUserId();
243        getSettingsForUser(userId).requestPermission(accessory, packageName, pi);
244    }
245
246    @Override
247    public void grantDevicePermission(UsbDevice device, int uid) {
248        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
249        final int userId = UserHandle.getUserId(uid);
250        getSettingsForUser(userId).grantDevicePermission(device, uid);
251    }
252
253    @Override
254    public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
255        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
256        final int userId = UserHandle.getUserId(uid);
257        getSettingsForUser(userId).grantAccessoryPermission(accessory, uid);
258    }
259
260    @Override
261    public boolean hasDefaults(String packageName, int userId) {
262        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
263        return getSettingsForUser(userId).hasDefaults(packageName);
264    }
265
266    @Override
267    public void clearDefaults(String packageName, int userId) {
268        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
269        getSettingsForUser(userId).clearDefaults(packageName);
270    }
271
272    @Override
273    public boolean isFunctionEnabled(String function) {
274        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
275        return mDeviceManager != null && mDeviceManager.isFunctionEnabled(function);
276    }
277
278    @Override
279    public void setCurrentFunction(String function) {
280        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
281
282        if (!isSupportedCurrentFunction(function)) {
283            Slog.w(TAG, "Caller of setCurrentFunction() requested unsupported USB function: "
284                    + function);
285            function = UsbManager.USB_FUNCTION_NONE;
286        }
287
288        if (mDeviceManager != null) {
289            mDeviceManager.setCurrentFunctions(function);
290        } else {
291            throw new IllegalStateException("USB device mode not supported");
292        }
293    }
294
295    private static boolean isSupportedCurrentFunction(String function) {
296        if (function == null) return true;
297
298        switch (function) {
299            case UsbManager.USB_FUNCTION_NONE:
300            case UsbManager.USB_FUNCTION_AUDIO_SOURCE:
301            case UsbManager.USB_FUNCTION_MIDI:
302            case UsbManager.USB_FUNCTION_MTP:
303            case UsbManager.USB_FUNCTION_PTP:
304            case UsbManager.USB_FUNCTION_RNDIS:
305                return true;
306        }
307
308        return false;
309    }
310
311    @Override
312    public void setUsbDataUnlocked(boolean unlocked) {
313        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
314        // If attempt to change USB function while file transfer is restricted, ensure that
315        // usb data is always locked, and return.
316        UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
317        if (userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
318            if (mDeviceManager != null) mDeviceManager.setUsbDataUnlocked(false);
319            return;
320        }
321        mDeviceManager.setUsbDataUnlocked(unlocked);
322    }
323
324    @Override
325    public boolean isUsbDataUnlocked() {
326        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
327        return mDeviceManager.isUsbDataUnlocked();
328    }
329
330    @Override
331    public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
332        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
333        mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey);
334    }
335
336    @Override
337    public void denyUsbDebugging() {
338        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
339        mDeviceManager.denyUsbDebugging();
340    }
341
342    @Override
343    public void clearUsbDebuggingKeys() {
344        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
345        mDeviceManager.clearUsbDebuggingKeys();
346    }
347
348    @Override
349    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
350        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
351        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
352
353        pw.println("USB Manager State:");
354        if (mDeviceManager != null) {
355            mDeviceManager.dump(fd, pw);
356        }
357        if (mHostManager != null) {
358            mHostManager.dump(fd, pw);
359        }
360        mAlsaManager.dump(fd, pw);
361
362        synchronized (mLock) {
363            for (int i = 0; i < mSettingsByUser.size(); i++) {
364                final int userId = mSettingsByUser.keyAt(i);
365                final UsbSettingsManager settings = mSettingsByUser.valueAt(i);
366                pw.increaseIndent();
367                pw.println("Settings for user " + userId + ":");
368                settings.dump(fd, pw);
369                pw.decreaseIndent();
370            }
371        }
372        pw.decreaseIndent();
373    }
374}
375