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.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.PackageManager;
25import android.hardware.usb.IUsbManager;
26import android.hardware.usb.UsbAccessory;
27import android.hardware.usb.UsbDevice;
28import android.os.Bundle;
29import android.os.ParcelFileDescriptor;
30import android.os.UserHandle;
31import android.util.SparseArray;
32
33import com.android.internal.annotations.GuardedBy;
34import com.android.internal.util.IndentingPrintWriter;
35
36import java.io.File;
37import java.io.FileDescriptor;
38import java.io.PrintWriter;
39
40/**
41 * UsbService manages all USB related state, including both host and device support.
42 * Host related events and calls are delegated to UsbHostManager, and device related
43 * support is delegated to UsbDeviceManager.
44 */
45public class UsbService extends IUsbManager.Stub {
46    private static final String TAG = "UsbService";
47
48    private final Context mContext;
49
50    private UsbDeviceManager mDeviceManager;
51    private UsbHostManager mHostManager;
52
53    private final Object mLock = new Object();
54
55    /** Map from {@link UserHandle} to {@link UsbSettingsManager} */
56    @GuardedBy("mLock")
57    private final SparseArray<UsbSettingsManager>
58            mSettingsByUser = new SparseArray<UsbSettingsManager>();
59
60    private UsbSettingsManager getSettingsForUser(int userId) {
61        synchronized (mLock) {
62            UsbSettingsManager settings = mSettingsByUser.get(userId);
63            if (settings == null) {
64                settings = new UsbSettingsManager(mContext, new UserHandle(userId));
65                mSettingsByUser.put(userId, settings);
66            }
67            return settings;
68        }
69    }
70
71    public UsbService(Context context) {
72        mContext = context;
73
74        final PackageManager pm = mContext.getPackageManager();
75        if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
76            mHostManager = new UsbHostManager(context);
77        }
78        if (new File("/sys/class/android_usb").exists()) {
79            mDeviceManager = new UsbDeviceManager(context);
80        }
81
82        setCurrentUser(UserHandle.USER_OWNER);
83
84        final IntentFilter userFilter = new IntentFilter();
85        userFilter.addAction(Intent.ACTION_USER_SWITCHED);
86        userFilter.addAction(Intent.ACTION_USER_STOPPED);
87        mContext.registerReceiver(mUserReceiver, userFilter, null, null);
88    }
89
90    private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
91        @Override
92        public void onReceive(Context context, Intent intent) {
93            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
94            final String action = intent.getAction();
95            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
96                setCurrentUser(userId);
97            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
98                synchronized (mLock) {
99                    mSettingsByUser.remove(userId);
100                }
101            }
102        }
103    };
104
105    private void setCurrentUser(int userId) {
106        final UsbSettingsManager userSettings = getSettingsForUser(userId);
107        if (mHostManager != null) {
108            mHostManager.setCurrentSettings(userSettings);
109        }
110        if (mDeviceManager != null) {
111            mDeviceManager.setCurrentSettings(userSettings);
112        }
113    }
114
115    public void systemReady() {
116        if (mDeviceManager != null) {
117            mDeviceManager.systemReady();
118        }
119        if (mHostManager != null) {
120            mHostManager.systemReady();
121        }
122    }
123
124    /* Returns a list of all currently attached USB devices (host mdoe) */
125    @Override
126    public void getDeviceList(Bundle devices) {
127        if (mHostManager != null) {
128            mHostManager.getDeviceList(devices);
129        }
130    }
131
132    /* Opens the specified USB device (host mode) */
133    @Override
134    public ParcelFileDescriptor openDevice(String deviceName) {
135        if (mHostManager != null) {
136            return mHostManager.openDevice(deviceName);
137        } else {
138            return null;
139        }
140    }
141
142    /* returns the currently attached USB accessory (device mode) */
143    @Override
144    public UsbAccessory getCurrentAccessory() {
145        if (mDeviceManager != null) {
146            return mDeviceManager.getCurrentAccessory();
147        } else {
148            return null;
149        }
150    }
151
152    /* opens the currently attached USB accessory (device mode) */
153    @Override
154    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
155        if (mDeviceManager != null) {
156            return mDeviceManager.openAccessory(accessory);
157        } else {
158            return null;
159        }
160    }
161
162    @Override
163    public void setDevicePackage(UsbDevice device, String packageName, int userId) {
164        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
165        getSettingsForUser(userId).setDevicePackage(device, packageName);
166    }
167
168    @Override
169    public void setAccessoryPackage(UsbAccessory accessory, String packageName, int userId) {
170        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
171        getSettingsForUser(userId).setAccessoryPackage(accessory, packageName);
172    }
173
174    @Override
175    public boolean hasDevicePermission(UsbDevice device) {
176        final int userId = UserHandle.getCallingUserId();
177        return getSettingsForUser(userId).hasPermission(device);
178    }
179
180    @Override
181    public boolean hasAccessoryPermission(UsbAccessory accessory) {
182        final int userId = UserHandle.getCallingUserId();
183        return getSettingsForUser(userId).hasPermission(accessory);
184    }
185
186    @Override
187    public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) {
188        final int userId = UserHandle.getCallingUserId();
189        getSettingsForUser(userId).requestPermission(device, packageName, pi);
190    }
191
192    @Override
193    public void requestAccessoryPermission(
194            UsbAccessory accessory, String packageName, PendingIntent pi) {
195        final int userId = UserHandle.getCallingUserId();
196        getSettingsForUser(userId).requestPermission(accessory, packageName, pi);
197    }
198
199    @Override
200    public void grantDevicePermission(UsbDevice device, int uid) {
201        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
202        final int userId = UserHandle.getUserId(uid);
203        getSettingsForUser(userId).grantDevicePermission(device, uid);
204    }
205
206    @Override
207    public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
208        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
209        final int userId = UserHandle.getUserId(uid);
210        getSettingsForUser(userId).grantAccessoryPermission(accessory, uid);
211    }
212
213    @Override
214    public boolean hasDefaults(String packageName, int userId) {
215        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
216        return getSettingsForUser(userId).hasDefaults(packageName);
217    }
218
219    @Override
220    public void clearDefaults(String packageName, int userId) {
221        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
222        getSettingsForUser(userId).clearDefaults(packageName);
223    }
224
225    @Override
226    public void setCurrentFunction(String function, boolean makeDefault) {
227        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
228        if (mDeviceManager != null) {
229            mDeviceManager.setCurrentFunctions(function, makeDefault);
230        } else {
231            throw new IllegalStateException("USB device mode not supported");
232        }
233    }
234
235    @Override
236    public void setMassStorageBackingFile(String path) {
237        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
238        if (mDeviceManager != null) {
239            mDeviceManager.setMassStorageBackingFile(path);
240        } else {
241            throw new IllegalStateException("USB device mode not supported");
242        }
243    }
244
245    @Override
246    public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
247        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
248        mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey);
249    }
250
251    @Override
252    public void denyUsbDebugging() {
253        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
254        mDeviceManager.denyUsbDebugging();
255    }
256
257    @Override
258    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
259        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
260        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
261
262        pw.println("USB Manager State:");
263        if (mDeviceManager != null) {
264            mDeviceManager.dump(fd, pw);
265        }
266        if (mHostManager != null) {
267            mHostManager.dump(fd, pw);
268        }
269
270        synchronized (mLock) {
271            for (int i = 0; i < mSettingsByUser.size(); i++) {
272                final int userId = mSettingsByUser.keyAt(i);
273                final UsbSettingsManager settings = mSettingsByUser.valueAt(i);
274                pw.increaseIndent();
275                pw.println("Settings for user " + userId + ":");
276                settings.dump(fd, pw);
277                pw.decreaseIndent();
278            }
279        }
280        pw.decreaseIndent();
281    }
282}
283