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_SYSTEM);
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        mDeviceManager.setUsbDataUnlocked(unlocked);
326    }
327
328    @Override
329    public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
330        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
331        mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey);
332    }
333
334    @Override
335    public void denyUsbDebugging() {
336        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
337        mDeviceManager.denyUsbDebugging();
338    }
339
340    @Override
341    public void clearUsbDebuggingKeys() {
342        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
343        mDeviceManager.clearUsbDebuggingKeys();
344    }
345
346    @Override
347    public UsbPort[] getPorts() {
348        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
349
350        final long ident = Binder.clearCallingIdentity();
351        try {
352            return mPortManager != null ? mPortManager.getPorts() : null;
353        } finally {
354            Binder.restoreCallingIdentity(ident);
355        }
356    }
357
358    @Override
359    public UsbPortStatus getPortStatus(String portId) {
360        Preconditions.checkNotNull(portId, "portId must not be null");
361        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
362
363        final long ident = Binder.clearCallingIdentity();
364        try {
365            return mPortManager != null ? mPortManager.getPortStatus(portId) : null;
366        } finally {
367            Binder.restoreCallingIdentity(ident);
368        }
369    }
370
371    @Override
372    public void setPortRoles(String portId, int powerRole, int dataRole) {
373        Preconditions.checkNotNull(portId, "portId must not be null");
374        UsbPort.checkRoles(powerRole, dataRole);
375        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
376
377        final long ident = Binder.clearCallingIdentity();
378        try {
379            if (mPortManager != null) {
380                mPortManager.setPortRoles(portId, powerRole, dataRole, null);
381            }
382        } finally {
383            Binder.restoreCallingIdentity(ident);
384        }
385    }
386
387    @Override
388    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
389        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
390
391        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
392        final long ident = Binder.clearCallingIdentity();
393        try {
394            if (args == null || args.length == 0 || "-a".equals(args[0])) {
395                pw.println("USB Manager State:");
396                pw.increaseIndent();
397                if (mDeviceManager != null) {
398                    mDeviceManager.dump(pw);
399                }
400                if (mHostManager != null) {
401                    mHostManager.dump(pw);
402                }
403                if (mPortManager != null) {
404                    mPortManager.dump(pw);
405                }
406                mAlsaManager.dump(pw);
407
408                synchronized (mLock) {
409                    for (int i = 0; i < mSettingsByUser.size(); i++) {
410                        final int userId = mSettingsByUser.keyAt(i);
411                        final UsbSettingsManager settings = mSettingsByUser.valueAt(i);
412                        pw.println("Settings for user " + userId + ":");
413                        pw.increaseIndent();
414                        settings.dump(pw);
415                        pw.decreaseIndent();
416                    }
417                }
418            } else if (args.length == 4 && "set-port-roles".equals(args[0])) {
419                final String portId = args[1];
420                final int powerRole;
421                switch (args[2]) {
422                    case "source":
423                        powerRole = UsbPort.POWER_ROLE_SOURCE;
424                        break;
425                    case "sink":
426                        powerRole = UsbPort.POWER_ROLE_SINK;
427                        break;
428                    case "no-power":
429                        powerRole = 0;
430                        break;
431                    default:
432                        pw.println("Invalid power role: " + args[2]);
433                        return;
434                }
435                final int dataRole;
436                switch (args[3]) {
437                    case "host":
438                        dataRole = UsbPort.DATA_ROLE_HOST;
439                        break;
440                    case "device":
441                        dataRole = UsbPort.DATA_ROLE_DEVICE;
442                        break;
443                    case "no-data":
444                        dataRole = 0;
445                        break;
446                    default:
447                        pw.println("Invalid data role: " + args[3]);
448                        return;
449                }
450                if (mPortManager != null) {
451                    mPortManager.setPortRoles(portId, powerRole, dataRole, pw);
452                    // Note: It might take some time for the side-effects of this operation
453                    // to be fully applied by the kernel since the driver may need to
454                    // renegotiate the USB port mode.  If this proves to be an issue
455                    // during debugging, it might be worth adding a sleep here before
456                    // dumping the new state.
457                    pw.println();
458                    mPortManager.dump(pw);
459                }
460            } else if (args.length == 3 && "add-port".equals(args[0])) {
461                final String portId = args[1];
462                final int supportedModes;
463                switch (args[2]) {
464                    case "ufp":
465                        supportedModes = UsbPort.MODE_UFP;
466                        break;
467                    case "dfp":
468                        supportedModes = UsbPort.MODE_DFP;
469                        break;
470                    case "dual":
471                        supportedModes = UsbPort.MODE_DUAL;
472                        break;
473                    case "none":
474                        supportedModes = 0;
475                        break;
476                    default:
477                        pw.println("Invalid mode: " + args[2]);
478                        return;
479                }
480                if (mPortManager != null) {
481                    mPortManager.addSimulatedPort(portId, supportedModes, pw);
482                    pw.println();
483                    mPortManager.dump(pw);
484                }
485            } else if (args.length == 5 && "connect-port".equals(args[0])) {
486                final String portId = args[1];
487                final int mode;
488                final boolean canChangeMode = args[2].endsWith("?");
489                switch (canChangeMode ? removeLastChar(args[2]) : args[2]) {
490                    case "ufp":
491                        mode = UsbPort.MODE_UFP;
492                        break;
493                    case "dfp":
494                        mode = UsbPort.MODE_DFP;
495                        break;
496                    default:
497                        pw.println("Invalid mode: " + args[2]);
498                        return;
499                }
500                final int powerRole;
501                final boolean canChangePowerRole = args[3].endsWith("?");
502                switch (canChangePowerRole ? removeLastChar(args[3]) : args[3]) {
503                    case "source":
504                        powerRole = UsbPort.POWER_ROLE_SOURCE;
505                        break;
506                    case "sink":
507                        powerRole = UsbPort.POWER_ROLE_SINK;
508                        break;
509                    default:
510                        pw.println("Invalid power role: " + args[3]);
511                        return;
512                }
513                final int dataRole;
514                final boolean canChangeDataRole = args[4].endsWith("?");
515                switch (canChangeDataRole ? removeLastChar(args[4]) : args[4]) {
516                    case "host":
517                        dataRole = UsbPort.DATA_ROLE_HOST;
518                        break;
519                    case "device":
520                        dataRole = UsbPort.DATA_ROLE_DEVICE;
521                        break;
522                    default:
523                        pw.println("Invalid data role: " + args[4]);
524                        return;
525                }
526                if (mPortManager != null) {
527                    mPortManager.connectSimulatedPort(portId, mode, canChangeMode,
528                            powerRole, canChangePowerRole, dataRole, canChangeDataRole, pw);
529                    pw.println();
530                    mPortManager.dump(pw);
531                }
532            } else if (args.length == 2 && "disconnect-port".equals(args[0])) {
533                final String portId = args[1];
534                if (mPortManager != null) {
535                    mPortManager.disconnectSimulatedPort(portId, pw);
536                    pw.println();
537                    mPortManager.dump(pw);
538                }
539            } else if (args.length == 2 && "remove-port".equals(args[0])) {
540                final String portId = args[1];
541                if (mPortManager != null) {
542                    mPortManager.removeSimulatedPort(portId, pw);
543                    pw.println();
544                    mPortManager.dump(pw);
545                }
546            } else if (args.length == 1 && "reset".equals(args[0])) {
547                if (mPortManager != null) {
548                    mPortManager.resetSimulation(pw);
549                    pw.println();
550                    mPortManager.dump(pw);
551                }
552            } else if (args.length == 1 && "ports".equals(args[0])) {
553                if (mPortManager != null) {
554                    mPortManager.dump(pw);
555                }
556            } else {
557                pw.println("Dump current USB state or issue command:");
558                pw.println("  ports");
559                pw.println("  set-port-roles <id> <source|sink|no-power> <host|device|no-data>");
560                pw.println("  add-port <id> <ufp|dfp|dual|none>");
561                pw.println("  connect-port <id> <ufp|dfp><?> <source|sink><?> <host|device><?>");
562                pw.println("    (add ? suffix if mode, power role, or data role can be changed)");
563                pw.println("  disconnect-port <id>");
564                pw.println("  remove-port <id>");
565                pw.println("  reset");
566                pw.println();
567                pw.println("Example USB type C port role switch:");
568                pw.println("  dumpsys usb set-port-roles \"default\" source device");
569                pw.println();
570                pw.println("Example USB type C port simulation with full capabilities:");
571                pw.println("  dumpsys usb add-port \"matrix\" dual");
572                pw.println("  dumpsys usb connect-port \"matrix\" ufp? sink? device?");
573                pw.println("  dumpsys usb ports");
574                pw.println("  dumpsys usb disconnect-port \"matrix\"");
575                pw.println("  dumpsys usb remove-port \"matrix\"");
576                pw.println("  dumpsys usb reset");
577                pw.println();
578                pw.println("Example USB type C port where only power role can be changed:");
579                pw.println("  dumpsys usb add-port \"matrix\" dual");
580                pw.println("  dumpsys usb connect-port \"matrix\" dfp source? host");
581                pw.println("  dumpsys usb reset");
582                pw.println();
583                pw.println("Example USB OTG port where id pin determines function:");
584                pw.println("  dumpsys usb add-port \"matrix\" dual");
585                pw.println("  dumpsys usb connect-port \"matrix\" dfp source host");
586                pw.println("  dumpsys usb reset");
587                pw.println();
588                pw.println("Example USB device-only port:");
589                pw.println("  dumpsys usb add-port \"matrix\" ufp");
590                pw.println("  dumpsys usb connect-port \"matrix\" ufp sink device");
591                pw.println("  dumpsys usb reset");
592            }
593        } finally {
594            Binder.restoreCallingIdentity(ident);
595        }
596    }
597
598    private static final String removeLastChar(String value) {
599        return value.substring(0, value.length() - 1);
600    }
601}
602