UsbService.java revision 76c4c6668a1486bc003ab0c585bb1f41d16e27a7
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.hardware.usb.UsbPort;
31import android.hardware.usb.UsbPortStatus;
32import android.os.Binder;
33import android.os.Bundle;
34import android.os.ParcelFileDescriptor;
35import android.os.UserHandle;
36import android.os.UserManager;
37import android.util.Slog;
38import android.util.SparseArray;
39
40import com.android.internal.annotations.GuardedBy;
41import com.android.internal.util.IndentingPrintWriter;
42import com.android.internal.util.Preconditions;
43import com.android.server.SystemService;
44
45import java.io.File;
46import java.io.FileDescriptor;
47import java.io.PrintWriter;
48
49/**
50 * UsbService manages all USB related state, including both host and device support.
51 * Host related events and calls are delegated to UsbHostManager, and device related
52 * support is delegated to UsbDeviceManager.
53 */
54public class UsbService extends IUsbManager.Stub {
55
56    public static class Lifecycle extends SystemService {
57        private UsbService mUsbService;
58
59        public Lifecycle(Context context) {
60            super(context);
61        }
62
63        @Override
64        public void onStart() {
65            mUsbService = new UsbService(getContext());
66            publishBinderService(Context.USB_SERVICE, mUsbService);
67        }
68
69        @Override
70        public void onBootPhase(int phase) {
71            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
72                mUsbService.systemReady();
73            } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
74                mUsbService.bootCompleted();
75            }
76        }
77    }
78
79    private static final String TAG = "UsbService";
80
81    private final Context mContext;
82
83    private UsbDeviceManager mDeviceManager;
84    private UsbHostManager mHostManager;
85    private UsbPortManager mPortManager;
86    private final UsbAlsaManager mAlsaManager;
87
88    private final Object mLock = new Object();
89
90    /** Map from {@link UserHandle} to {@link UsbSettingsManager} */
91    @GuardedBy("mLock")
92    private final SparseArray<UsbSettingsManager>
93            mSettingsByUser = new SparseArray<UsbSettingsManager>();
94
95    private UsbSettingsManager getSettingsForUser(int userId) {
96        synchronized (mLock) {
97            UsbSettingsManager settings = mSettingsByUser.get(userId);
98            if (settings == null) {
99                settings = new UsbSettingsManager(mContext, new UserHandle(userId));
100                mSettingsByUser.put(userId, settings);
101            }
102            return settings;
103        }
104    }
105
106    public UsbService(Context context) {
107        mContext = context;
108
109        mAlsaManager = new UsbAlsaManager(context);
110
111        final PackageManager pm = mContext.getPackageManager();
112        if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
113            mHostManager = new UsbHostManager(context, mAlsaManager);
114        }
115        if (new File("/sys/class/android_usb").exists()) {
116            mDeviceManager = new UsbDeviceManager(context, mAlsaManager);
117        }
118        if (mHostManager != null || mDeviceManager != null) {
119            mPortManager = new UsbPortManager(context);
120        }
121
122        setCurrentUser(UserHandle.USER_OWNER);
123
124        final IntentFilter filter = new IntentFilter();
125        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
126        filter.addAction(Intent.ACTION_USER_SWITCHED);
127        filter.addAction(Intent.ACTION_USER_STOPPED);
128        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
129        mContext.registerReceiver(mReceiver, filter, null, null);
130    }
131
132    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
133        @Override
134        public void onReceive(Context context, Intent intent) {
135            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
136            final String action = intent.getAction();
137            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
138                setCurrentUser(userId);
139            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
140                synchronized (mLock) {
141                    mSettingsByUser.remove(userId);
142                }
143            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
144                    .equals(action)) {
145                if (mDeviceManager != null) {
146                    mDeviceManager.updateUserRestrictions();
147                }
148            }
149        }
150    };
151
152    private void setCurrentUser(int userId) {
153        final UsbSettingsManager userSettings = getSettingsForUser(userId);
154        if (mHostManager != null) {
155            mHostManager.setCurrentSettings(userSettings);
156        }
157        if (mDeviceManager != null) {
158            mDeviceManager.setCurrentUser(userId, userSettings);
159        }
160    }
161
162    public void systemReady() {
163        mAlsaManager.systemReady();
164
165        if (mDeviceManager != null) {
166            mDeviceManager.systemReady();
167        }
168        if (mHostManager != null) {
169            mHostManager.systemReady();
170        }
171        if (mPortManager != null) {
172            mPortManager.systemReady();
173        }
174    }
175
176    public void bootCompleted() {
177        if (mDeviceManager != null) {
178            mDeviceManager.bootCompleted();
179        }
180    }
181
182    /* Returns a list of all currently attached USB devices (host mdoe) */
183    @Override
184    public void getDeviceList(Bundle devices) {
185        if (mHostManager != null) {
186            mHostManager.getDeviceList(devices);
187        }
188    }
189
190    /* Opens the specified USB device (host mode) */
191    @Override
192    public ParcelFileDescriptor openDevice(String deviceName) {
193        if (mHostManager != null) {
194            return mHostManager.openDevice(deviceName);
195        } else {
196            return null;
197        }
198    }
199
200    /* returns the currently attached USB accessory (device mode) */
201    @Override
202    public UsbAccessory getCurrentAccessory() {
203        if (mDeviceManager != null) {
204            return mDeviceManager.getCurrentAccessory();
205        } else {
206            return null;
207        }
208    }
209
210    /* opens the currently attached USB accessory (device mode) */
211    @Override
212    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
213        if (mDeviceManager != null) {
214            return mDeviceManager.openAccessory(accessory);
215        } else {
216            return null;
217        }
218    }
219
220    @Override
221    public void setDevicePackage(UsbDevice device, String packageName, int userId) {
222        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
223        getSettingsForUser(userId).setDevicePackage(device, packageName);
224    }
225
226    @Override
227    public void setAccessoryPackage(UsbAccessory accessory, String packageName, int userId) {
228        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
229        getSettingsForUser(userId).setAccessoryPackage(accessory, packageName);
230    }
231
232    @Override
233    public boolean hasDevicePermission(UsbDevice device) {
234        final int userId = UserHandle.getCallingUserId();
235        return getSettingsForUser(userId).hasPermission(device);
236    }
237
238    @Override
239    public boolean hasAccessoryPermission(UsbAccessory accessory) {
240        final int userId = UserHandle.getCallingUserId();
241        return getSettingsForUser(userId).hasPermission(accessory);
242    }
243
244    @Override
245    public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) {
246        final int userId = UserHandle.getCallingUserId();
247        getSettingsForUser(userId).requestPermission(device, packageName, pi);
248    }
249
250    @Override
251    public void requestAccessoryPermission(
252            UsbAccessory accessory, String packageName, PendingIntent pi) {
253        final int userId = UserHandle.getCallingUserId();
254        getSettingsForUser(userId).requestPermission(accessory, packageName, pi);
255    }
256
257    @Override
258    public void grantDevicePermission(UsbDevice device, int uid) {
259        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
260        final int userId = UserHandle.getUserId(uid);
261        getSettingsForUser(userId).grantDevicePermission(device, uid);
262    }
263
264    @Override
265    public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
266        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
267        final int userId = UserHandle.getUserId(uid);
268        getSettingsForUser(userId).grantAccessoryPermission(accessory, uid);
269    }
270
271    @Override
272    public boolean hasDefaults(String packageName, int userId) {
273        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
274        return getSettingsForUser(userId).hasDefaults(packageName);
275    }
276
277    @Override
278    public void clearDefaults(String packageName, int userId) {
279        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
280        getSettingsForUser(userId).clearDefaults(packageName);
281    }
282
283    @Override
284    public boolean isFunctionEnabled(String function) {
285        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
286        return mDeviceManager != null && mDeviceManager.isFunctionEnabled(function);
287    }
288
289    @Override
290    public void setCurrentFunction(String function) {
291        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
292
293        if (!isSupportedCurrentFunction(function)) {
294            Slog.w(TAG, "Caller of setCurrentFunction() requested unsupported USB function: "
295                    + function);
296            function = UsbManager.USB_FUNCTION_NONE;
297        }
298
299        if (mDeviceManager != null) {
300            mDeviceManager.setCurrentFunctions(function);
301        } else {
302            throw new IllegalStateException("USB device mode not supported");
303        }
304    }
305
306    private static boolean isSupportedCurrentFunction(String function) {
307        if (function == null) return true;
308
309        switch (function) {
310            case UsbManager.USB_FUNCTION_NONE:
311            case UsbManager.USB_FUNCTION_AUDIO_SOURCE:
312            case UsbManager.USB_FUNCTION_MIDI:
313            case UsbManager.USB_FUNCTION_MTP:
314            case UsbManager.USB_FUNCTION_PTP:
315            case UsbManager.USB_FUNCTION_RNDIS:
316                return true;
317        }
318
319        return false;
320    }
321
322    @Override
323    public void setUsbDataUnlocked(boolean unlocked) {
324        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
325        // If attempt to change USB function while file transfer is restricted, ensure that
326        // usb data is always locked, and return.
327        UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
328        if (userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
329            if (mDeviceManager != null) mDeviceManager.setUsbDataUnlocked(false);
330            return;
331        }
332        mDeviceManager.setUsbDataUnlocked(unlocked);
333    }
334
335    @Override
336    public boolean isUsbDataUnlocked() {
337        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
338        return mDeviceManager.isUsbDataUnlocked();
339    }
340
341    @Override
342    public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
343        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
344        mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey);
345    }
346
347    @Override
348    public void denyUsbDebugging() {
349        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
350        mDeviceManager.denyUsbDebugging();
351    }
352
353    @Override
354    public void clearUsbDebuggingKeys() {
355        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
356        mDeviceManager.clearUsbDebuggingKeys();
357    }
358
359    @Override
360    public UsbPort[] getPorts() {
361        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
362
363        final long ident = Binder.clearCallingIdentity();
364        try {
365            return mPortManager != null ? mPortManager.getPorts() : null;
366        } finally {
367            Binder.restoreCallingIdentity(ident);
368        }
369    }
370
371    @Override
372    public UsbPortStatus getPortStatus(String portId) {
373        Preconditions.checkNotNull(portId, "portId must not be null");
374        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
375
376        final long ident = Binder.clearCallingIdentity();
377        try {
378            return mPortManager != null ? mPortManager.getPortStatus(portId) : null;
379        } finally {
380            Binder.restoreCallingIdentity(ident);
381        }
382    }
383
384    @Override
385    public void setPortRoles(String portId, int powerRole, int dataRole) {
386        Preconditions.checkNotNull(portId, "portId must not be null");
387        UsbPort.checkRoles(powerRole, dataRole);
388        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
389
390        final long ident = Binder.clearCallingIdentity();
391        try {
392            if (mPortManager != null) {
393                mPortManager.setPortRoles(portId, powerRole, dataRole, null);
394            }
395        } finally {
396            Binder.restoreCallingIdentity(ident);
397        }
398    }
399
400    @Override
401    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
402        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
403
404        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
405        final long ident = Binder.clearCallingIdentity();
406        try {
407            if (args == null || args.length == 0 || "-a".equals(args[0])) {
408                pw.println("USB Manager State:");
409                pw.increaseIndent();
410                if (mDeviceManager != null) {
411                    mDeviceManager.dump(pw);
412                }
413                if (mHostManager != null) {
414                    mHostManager.dump(pw);
415                }
416                if (mPortManager != null) {
417                    mPortManager.dump(pw);
418                }
419                mAlsaManager.dump(pw);
420
421                synchronized (mLock) {
422                    for (int i = 0; i < mSettingsByUser.size(); i++) {
423                        final int userId = mSettingsByUser.keyAt(i);
424                        final UsbSettingsManager settings = mSettingsByUser.valueAt(i);
425                        pw.println("Settings for user " + userId + ":");
426                        pw.increaseIndent();
427                        settings.dump(pw);
428                        pw.decreaseIndent();
429                    }
430                }
431            } else if (args.length == 4 && "set-port-roles".equals(args[0])) {
432                final String portId = args[1];
433                final int powerRole;
434                switch (args[2]) {
435                    case "source":
436                        powerRole = UsbPort.POWER_ROLE_SOURCE;
437                        break;
438                    case "sink":
439                        powerRole = UsbPort.POWER_ROLE_SINK;
440                        break;
441                    case "no-power":
442                        powerRole = 0;
443                        break;
444                    default:
445                        pw.println("Invalid power role: " + args[2]);
446                        return;
447                }
448                final int dataRole;
449                switch (args[3]) {
450                    case "host":
451                        dataRole = UsbPort.DATA_ROLE_HOST;
452                        break;
453                    case "device":
454                        dataRole = UsbPort.DATA_ROLE_DEVICE;
455                        break;
456                    case "no-data":
457                        dataRole = 0;
458                        break;
459                    default:
460                        pw.println("Invalid data role: " + args[3]);
461                        return;
462                }
463                if (mPortManager != null) {
464                    mPortManager.setPortRoles(portId, powerRole, dataRole, pw);
465                    // Note: It might take some time for the side-effects of this operation
466                    // to be fully applied by the kernel since the driver may need to
467                    // renegotiate the USB port mode.  If this proves to be an issue
468                    // during debugging, it might be worth adding a sleep here before
469                    // dumping the new state.
470                    pw.println();
471                    mPortManager.dump(pw);
472                }
473            } else if (args.length == 3 && "add-port".equals(args[0])) {
474                final String portId = args[1];
475                final int supportedModes;
476                switch (args[2]) {
477                    case "ufp":
478                        supportedModes = UsbPort.MODE_UFP;
479                        break;
480                    case "dfp":
481                        supportedModes = UsbPort.MODE_DFP;
482                        break;
483                    case "dual":
484                        supportedModes = UsbPort.MODE_DUAL;
485                        break;
486                    case "none":
487                        supportedModes = 0;
488                        break;
489                    default:
490                        pw.println("Invalid mode: " + args[2]);
491                        return;
492                }
493                if (mPortManager != null) {
494                    mPortManager.addSimulatedPort(portId, supportedModes, pw);
495                    pw.println();
496                    mPortManager.dump(pw);
497                }
498            } else if (args.length == 5 && "connect-port".equals(args[0])) {
499                final String portId = args[1];
500                final int mode;
501                final boolean canChangeMode = args[2].endsWith("?");
502                switch (canChangeMode ? removeLastChar(args[2]) : args[2]) {
503                    case "ufp":
504                        mode = UsbPort.MODE_UFP;
505                        break;
506                    case "dfp":
507                        mode = UsbPort.MODE_DFP;
508                        break;
509                    default:
510                        pw.println("Invalid mode: " + args[2]);
511                        return;
512                }
513                final int powerRole;
514                final boolean canChangePowerRole = args[3].endsWith("?");
515                switch (canChangePowerRole ? removeLastChar(args[3]) : args[3]) {
516                    case "source":
517                        powerRole = UsbPort.POWER_ROLE_SOURCE;
518                        break;
519                    case "sink":
520                        powerRole = UsbPort.POWER_ROLE_SINK;
521                        break;
522                    default:
523                        pw.println("Invalid power role: " + args[3]);
524                        return;
525                }
526                final int dataRole;
527                final boolean canChangeDataRole = args[4].endsWith("?");
528                switch (canChangeDataRole ? removeLastChar(args[4]) : args[4]) {
529                    case "host":
530                        dataRole = UsbPort.DATA_ROLE_HOST;
531                        break;
532                    case "device":
533                        dataRole = UsbPort.DATA_ROLE_DEVICE;
534                        break;
535                    default:
536                        pw.println("Invalid data role: " + args[4]);
537                        return;
538                }
539                if (mPortManager != null) {
540                    mPortManager.connectSimulatedPort(portId, mode, canChangeMode,
541                            powerRole, canChangePowerRole, dataRole, canChangeDataRole, pw);
542                    pw.println();
543                    mPortManager.dump(pw);
544                }
545            } else if (args.length == 2 && "disconnect-port".equals(args[0])) {
546                final String portId = args[1];
547                if (mPortManager != null) {
548                    mPortManager.disconnectSimulatedPort(portId, pw);
549                    pw.println();
550                    mPortManager.dump(pw);
551                }
552            } else if (args.length == 2 && "remove-port".equals(args[0])) {
553                final String portId = args[1];
554                if (mPortManager != null) {
555                    mPortManager.removeSimulatedPort(portId, pw);
556                    pw.println();
557                    mPortManager.dump(pw);
558                }
559            } else if (args.length == 1 && "reset".equals(args[0])) {
560                if (mPortManager != null) {
561                    mPortManager.resetSimulation(pw);
562                    pw.println();
563                    mPortManager.dump(pw);
564                }
565            } else if (args.length == 1 && "ports".equals(args[0])) {
566                if (mPortManager != null) {
567                    mPortManager.dump(pw);
568                }
569            } else {
570                pw.println("Dump current USB state or issue command:");
571                pw.println("  ports");
572                pw.println("  set-port-roles <id> <source|sink|no-power> <host|device|no-data>");
573                pw.println("  add-port <id> <ufp|dfp|dual|none>");
574                pw.println("  connect-port <id> <ufp|dfp><?> <source|sink><?> <host|device><?>");
575                pw.println("    (add ? suffix if mode, power role, or data role can be changed)");
576                pw.println("  disconnect-port <id>");
577                pw.println("  remove-port <id>");
578                pw.println("  reset");
579                pw.println();
580                pw.println("Example USB type C port role switch:");
581                pw.println("  dumpsys usb set-port-roles \"default\" source device");
582                pw.println();
583                pw.println("Example USB type C port simulation with full capabilities:");
584                pw.println("  dumpsys usb add-port \"matrix\" dual");
585                pw.println("  dumpsys usb connect-port \"matrix\" ufp? sink? device?");
586                pw.println("  dumpsys usb ports");
587                pw.println("  dumpsys usb disconnect-port \"matrix\"");
588                pw.println("  dumpsys usb remove-port \"matrix\"");
589                pw.println("  dumpsys usb reset");
590                pw.println();
591                pw.println("Example USB type C port where only power role can be changed:");
592                pw.println("  dumpsys usb add-port \"matrix\" dual");
593                pw.println("  dumpsys usb connect-port \"matrix\" dfp source? host");
594                pw.println("  dumpsys usb reset");
595                pw.println();
596                pw.println("Example USB OTG port where id pin determines function:");
597                pw.println("  dumpsys usb add-port \"matrix\" dual");
598                pw.println("  dumpsys usb connect-port \"matrix\" dfp source host");
599                pw.println("  dumpsys usb reset");
600                pw.println();
601                pw.println("Example USB device-only port:");
602                pw.println("  dumpsys usb add-port \"matrix\" ufp");
603                pw.println("  dumpsys usb connect-port \"matrix\" ufp sink device");
604                pw.println("  dumpsys usb reset");
605            }
606        } finally {
607            Binder.restoreCallingIdentity(ident);
608        }
609    }
610
611    private static final String removeLastChar(String value) {
612        return value.substring(0, value.length() - 1);
613    }
614}
615