Merge "MIDI: Add virtual devices per user" into udc-qpr-dev

This commit is contained in:
Robert Wu
2023-07-12 18:41:40 +00:00
committed by Android (Google) Code Review

View File

@@ -16,7 +16,9 @@
package com.android.server.midi; package com.android.server.midi;
import android.Manifest;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothUuid; import android.bluetooth.BluetoothUuid;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@@ -48,6 +50,7 @@ import android.os.ParcelUuid;
import android.os.Process; import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager;
import android.util.EventLog; import android.util.EventLog;
import android.util.Log; import android.util.Log;
@@ -81,6 +84,11 @@ import java.util.concurrent.atomic.AtomicLong;
// 2. synchronized (mDeviceConnections) // 2. synchronized (mDeviceConnections)
//TODO Introduce a single lock object to lock the whole state and avoid the requirement above. //TODO Introduce a single lock object to lock the whole state and avoid the requirement above.
// All users should be able to connect to USB and Bluetooth MIDI devices.
// All users can create can install an app that provides, a Virtual MIDI Device Service.
// Users can not open virtual MIDI devices created by other users.
// getDevices() surfaces devices that can be opened by that user.
// openDevice() rejects devices that are cannot be opened by that user.
public class MidiService extends IMidiManager.Stub { public class MidiService extends IMidiManager.Stub {
public static class Lifecycle extends SystemService { public static class Lifecycle extends SystemService {
@@ -97,10 +105,21 @@ public class MidiService extends IMidiManager.Stub {
} }
@Override @Override
@RequiresPermission(allOf = {Manifest.permission.INTERACT_ACROSS_USERS},
anyOf = {Manifest.permission.QUERY_USERS,
Manifest.permission.CREATE_USERS,
Manifest.permission.MANAGE_USERS})
public void onUserStarting(@NonNull TargetUser user) {
mMidiService.onStartOrUnlockUser(user, false /* matchDirectBootUnaware */);
}
@Override
@RequiresPermission(allOf = {Manifest.permission.INTERACT_ACROSS_USERS},
anyOf = {Manifest.permission.QUERY_USERS,
Manifest.permission.CREATE_USERS,
Manifest.permission.MANAGE_USERS})
public void onUserUnlocking(@NonNull TargetUser user) { public void onUserUnlocking(@NonNull TargetUser user) {
if (user.getUserIdentifier() == UserHandle.USER_SYSTEM) { mMidiService.onStartOrUnlockUser(user, true /* matchDirectBootUnaware */);
mMidiService.onUnlockUser();
}
} }
} }
@@ -134,6 +153,7 @@ public class MidiService extends IMidiManager.Stub {
private int mNextDeviceId = 1; private int mNextDeviceId = 1;
private final PackageManager mPackageManager; private final PackageManager mPackageManager;
private final UserManager mUserManager;
private static final String MIDI_LEGACY_STRING = "MIDI 1.0"; private static final String MIDI_LEGACY_STRING = "MIDI 1.0";
private static final String MIDI_UNIVERSAL_STRING = "MIDI 2.0"; private static final String MIDI_UNIVERSAL_STRING = "MIDI 2.0";
@@ -159,21 +179,24 @@ public class MidiService extends IMidiManager.Stub {
private final HashSet<ParcelUuid> mNonMidiUUIDs = new HashSet<ParcelUuid>(); private final HashSet<ParcelUuid> mNonMidiUUIDs = new HashSet<ParcelUuid>();
// PackageMonitor for listening to package changes // PackageMonitor for listening to package changes
// uid is the uid of the package so use getChangingUserId() to fetch the userId.
private final PackageMonitor mPackageMonitor = new PackageMonitor() { private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override @Override
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
public void onPackageAdded(String packageName, int uid) { public void onPackageAdded(String packageName, int uid) {
addPackageDeviceServers(packageName); addPackageDeviceServers(packageName, getChangingUserId());
} }
@Override @Override
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
public void onPackageModified(String packageName) { public void onPackageModified(String packageName) {
removePackageDeviceServers(packageName); removePackageDeviceServers(packageName, getChangingUserId());
addPackageDeviceServers(packageName); addPackageDeviceServers(packageName, getChangingUserId());
} }
@Override @Override
public void onPackageRemoved(String packageName, int uid) { public void onPackageRemoved(String packageName, int uid) {
removePackageDeviceServers(packageName); removePackageDeviceServers(packageName, getChangingUserId());
} }
}; };
@@ -202,6 +225,10 @@ public class MidiService extends IMidiManager.Stub {
return mUid; return mUid;
} }
private int getUserId() {
return UserHandle.getUserId(mUid);
}
public void addListener(IMidiDeviceListener listener) { public void addListener(IMidiDeviceListener listener) {
if (mListeners.size() >= MAX_LISTENERS_PER_CLIENT) { if (mListeners.size() >= MAX_LISTENERS_PER_CLIENT) {
throw new SecurityException( throw new SecurityException(
@@ -219,8 +246,12 @@ public class MidiService extends IMidiManager.Stub {
} }
} }
public void addDeviceConnection(Device device, IMidiDeviceOpenCallback callback) { @RequiresPermission(anyOf = {Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Log.d(TAG, "addDeviceConnection() device:" + device); Manifest.permission.INTERACT_ACROSS_USERS,
Manifest.permission.INTERACT_ACROSS_PROFILES})
public void addDeviceConnection(Device device, IMidiDeviceOpenCallback callback,
int userId) {
Log.d(TAG, "addDeviceConnection() device:" + device + " userId:" + userId);
if (mDeviceConnections.size() >= MAX_CONNECTIONS_PER_CLIENT) { if (mDeviceConnections.size() >= MAX_CONNECTIONS_PER_CLIENT) {
Log.i(TAG, "too many MIDI connections for UID = " + mUid); Log.i(TAG, "too many MIDI connections for UID = " + mUid);
throw new SecurityException( throw new SecurityException(
@@ -228,7 +259,7 @@ public class MidiService extends IMidiManager.Stub {
} }
DeviceConnection connection = new DeviceConnection(device, this, callback); DeviceConnection connection = new DeviceConnection(device, this, callback);
mDeviceConnections.put(connection.getToken(), connection); mDeviceConnections.put(connection.getToken(), connection);
device.addDeviceConnection(connection); device.addDeviceConnection(connection, userId);
} }
// called from MidiService.closeDevice() // called from MidiService.closeDevice()
@@ -251,8 +282,8 @@ public class MidiService extends IMidiManager.Stub {
} }
public void deviceAdded(Device device) { public void deviceAdded(Device device) {
// ignore private devices that our client cannot access // ignore devices that our client cannot access
if (!device.isUidAllowed(mUid)) return; if (!device.isUidAllowed(mUid) || !device.isUserIdAllowed(getUserId())) return;
MidiDeviceInfo deviceInfo = device.getDeviceInfo(); MidiDeviceInfo deviceInfo = device.getDeviceInfo();
try { try {
@@ -265,8 +296,8 @@ public class MidiService extends IMidiManager.Stub {
} }
public void deviceRemoved(Device device) { public void deviceRemoved(Device device) {
// ignore private devices that our client cannot access // ignore devices that our client cannot access
if (!device.isUidAllowed(mUid)) return; if (!device.isUidAllowed(mUid) || !device.isUserIdAllowed(getUserId())) return;
MidiDeviceInfo deviceInfo = device.getDeviceInfo(); MidiDeviceInfo deviceInfo = device.getDeviceInfo();
try { try {
@@ -279,8 +310,8 @@ public class MidiService extends IMidiManager.Stub {
} }
public void deviceStatusChanged(Device device, MidiDeviceStatus status) { public void deviceStatusChanged(Device device, MidiDeviceStatus status) {
// ignore private devices that our client cannot access // ignore devices that our client cannot access
if (!device.isUidAllowed(mUid)) return; if (!device.isUidAllowed(mUid) || !device.isUserIdAllowed(getUserId())) return;
try { try {
for (IMidiDeviceListener listener : mListeners.values()) { for (IMidiDeviceListener listener : mListeners.values()) {
@@ -354,6 +385,8 @@ public class MidiService extends IMidiManager.Stub {
private final ServiceInfo mServiceInfo; private final ServiceInfo mServiceInfo;
// UID of device implementation // UID of device implementation
private final int mUid; private final int mUid;
// User Id of the app. Only used for virtual devices
private final int mUserId;
// ServiceConnection for implementing Service (virtual devices only) // ServiceConnection for implementing Service (virtual devices only)
// mServiceConnection is non-null when connected or attempting to connect to the service // mServiceConnection is non-null when connected or attempting to connect to the service
@@ -375,19 +408,24 @@ public class MidiService extends IMidiManager.Stub {
private AtomicInteger mTotalOutputBytes = new AtomicInteger(); private AtomicInteger mTotalOutputBytes = new AtomicInteger();
public Device(IMidiDeviceServer server, MidiDeviceInfo deviceInfo, public Device(IMidiDeviceServer server, MidiDeviceInfo deviceInfo,
ServiceInfo serviceInfo, int uid) { ServiceInfo serviceInfo, int uid, int userId) {
mDeviceInfo = deviceInfo; mDeviceInfo = deviceInfo;
mServiceInfo = serviceInfo; mServiceInfo = serviceInfo;
mUid = uid; mUid = uid;
mUserId = userId;
mBluetoothDevice = (BluetoothDevice)deviceInfo.getProperties().getParcelable( mBluetoothDevice = (BluetoothDevice)deviceInfo.getProperties().getParcelable(
MidiDeviceInfo.PROPERTY_BLUETOOTH_DEVICE, android.bluetooth.BluetoothDevice.class);; MidiDeviceInfo.PROPERTY_BLUETOOTH_DEVICE, android.bluetooth.BluetoothDevice.class);;
setDeviceServer(server); setDeviceServer(server);
} }
@RequiresPermission(anyOf = {Manifest.permission.QUERY_USERS,
Manifest.permission.CREATE_USERS,
Manifest.permission.MANAGE_USERS})
public Device(BluetoothDevice bluetoothDevice) { public Device(BluetoothDevice bluetoothDevice) {
mBluetoothDevice = bluetoothDevice; mBluetoothDevice = bluetoothDevice;
mServiceInfo = null; mServiceInfo = null;
mUid = mBluetoothServiceUid; mUid = mBluetoothServiceUid;
mUserId = mUserManager.getMainUser().getIdentifier();
} }
private void setDeviceServer(IMidiDeviceServer server) { private void setDeviceServer(IMidiDeviceServer server) {
@@ -468,11 +506,22 @@ public class MidiService extends IMidiManager.Stub {
return mUid; return mUid;
} }
public int getUserId() {
return mUserId;
}
public boolean isUidAllowed(int uid) { public boolean isUidAllowed(int uid) {
return (!mDeviceInfo.isPrivate() || mUid == uid); return (!mDeviceInfo.isPrivate() || mUid == uid);
} }
public void addDeviceConnection(DeviceConnection connection) { public boolean isUserIdAllowed(int userId) {
return (mDeviceInfo.getType() != MidiDeviceInfo.TYPE_VIRTUAL || mUserId == userId);
}
@RequiresPermission(anyOf = {Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Manifest.permission.INTERACT_ACROSS_USERS,
Manifest.permission.INTERACT_ACROSS_PROFILES})
public void addDeviceConnection(DeviceConnection connection, int userId) {
Log.d(TAG, "addDeviceConnection() [A] connection:" + connection); Log.d(TAG, "addDeviceConnection() [A] connection:" + connection);
synchronized (mDeviceConnections) { synchronized (mDeviceConnections) {
mDeviceConnectionsAdded.incrementAndGet(); mDeviceConnectionsAdded.incrementAndGet();
@@ -537,8 +586,8 @@ public class MidiService extends IMidiManager.Stub {
new ComponentName(mServiceInfo.packageName, mServiceInfo.name)); new ComponentName(mServiceInfo.packageName, mServiceInfo.name));
} }
if (!mContext.bindService(intent, mServiceConnection, if (!mContext.bindServiceAsUser(intent, mServiceConnection,
Context.BIND_AUTO_CREATE)) { Context.BIND_AUTO_CREATE, UserHandle.of(mUserId))) {
Log.e(TAG, "Unable to bind service: " + intent); Log.e(TAG, "Unable to bind service: " + intent);
setDeviceServer(null); setDeviceServer(null);
mServiceConnection = null; mServiceConnection = null;
@@ -886,6 +935,8 @@ public class MidiService extends IMidiManager.Stub {
public MidiService(Context context) { public MidiService(Context context) {
mContext = context; mContext = context;
mPackageManager = context.getPackageManager(); mPackageManager = context.getPackageManager();
mUserManager = mContext.getSystemService(UserManager.class);
mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
// TEMPORARY - Disable BTL-MIDI // TEMPORARY - Disable BTL-MIDI
//FIXME - b/25689266 //FIXME - b/25689266
@@ -913,32 +964,41 @@ public class MidiService extends IMidiManager.Stub {
// mNonMidiUUIDs.add(BluetoothUuid.BATTERY); // mNonMidiUUIDs.add(BluetoothUuid.BATTERY);
} }
private void onUnlockUser() { @RequiresPermission(allOf = {Manifest.permission.INTERACT_ACROSS_USERS},
mPackageMonitor.register(mContext, null, true); anyOf = {Manifest.permission.QUERY_USERS,
Manifest.permission.CREATE_USERS,
Manifest.permission.MANAGE_USERS})
private void onStartOrUnlockUser(TargetUser user, boolean matchDirectBootUnaware) {
Log.d(TAG, "onStartOrUnlockUser " + user.getUserIdentifier() + " matchDirectBootUnaware: "
+ matchDirectBootUnaware);
Intent intent = new Intent(MidiDeviceService.SERVICE_INTERFACE); Intent intent = new Intent(MidiDeviceService.SERVICE_INTERFACE);
List<ResolveInfo> resolveInfos = mPackageManager.queryIntentServices(intent, int resolveFlags = PackageManager.GET_META_DATA;
PackageManager.GET_META_DATA); if (matchDirectBootUnaware) {
resolveFlags |= PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
}
List<ResolveInfo> resolveInfos = mPackageManager.queryIntentServicesAsUser(intent,
resolveFlags, user.getUserIdentifier());
if (resolveInfos != null) { if (resolveInfos != null) {
int count = resolveInfos.size(); int count = resolveInfos.size();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo; ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
if (serviceInfo != null) { if (serviceInfo != null) {
addPackageDeviceServer(serviceInfo); addPackageDeviceServer(serviceInfo, user.getUserIdentifier());
} }
} }
} }
PackageInfo info; if (user.getUserIdentifier() == mUserManager.getMainUser().getIdentifier()) {
try { PackageInfo info;
info = mPackageManager.getPackageInfo(MidiManager.BLUETOOTH_MIDI_SERVICE_PACKAGE, 0); try {
} catch (PackageManager.NameNotFoundException e) { info = mPackageManager.getPackageInfoAsUser(
info = null; MidiManager.BLUETOOTH_MIDI_SERVICE_PACKAGE, 0, user.getUserIdentifier());
} } catch (PackageManager.NameNotFoundException e) {
if (info != null && info.applicationInfo != null) { info = null;
mBluetoothServiceUid = info.applicationInfo.uid; }
} else { if (info != null && info.applicationInfo != null) {
mBluetoothServiceUid = -1; mBluetoothServiceUid = info.applicationInfo.uid;
}
} }
} }
@@ -960,10 +1020,11 @@ public class MidiService extends IMidiManager.Stub {
// Inform listener of the status of all known devices. // Inform listener of the status of all known devices.
private void updateStickyDeviceStatus(int uid, IMidiDeviceListener listener) { private void updateStickyDeviceStatus(int uid, IMidiDeviceListener listener) {
int userId = UserHandle.getUserId(uid);
synchronized (mDevicesByInfo) { synchronized (mDevicesByInfo) {
for (Device device : mDevicesByInfo.values()) { for (Device device : mDevicesByInfo.values()) {
// ignore private devices that our client cannot access // ignore devices that our client cannot access
if (device.isUidAllowed(uid)) { if (device.isUidAllowed(uid) && device.isUserIdAllowed(userId)) {
try { try {
MidiDeviceStatus status = device.getDeviceStatus(); MidiDeviceStatus status = device.getDeviceStatus();
if (status != null) { if (status != null) {
@@ -989,10 +1050,11 @@ public class MidiService extends IMidiManager.Stub {
public MidiDeviceInfo[] getDevicesForTransport(int transport) { public MidiDeviceInfo[] getDevicesForTransport(int transport) {
ArrayList<MidiDeviceInfo> deviceInfos = new ArrayList<MidiDeviceInfo>(); ArrayList<MidiDeviceInfo> deviceInfos = new ArrayList<MidiDeviceInfo>();
int uid = Binder.getCallingUid(); int uid = Binder.getCallingUid();
int userId = getCallingUserId();
synchronized (mDevicesByInfo) { synchronized (mDevicesByInfo) {
for (Device device : mDevicesByInfo.values()) { for (Device device : mDevicesByInfo.values()) {
if (device.isUidAllowed(uid)) { if (device.isUidAllowed(uid) && device.isUserIdAllowed(userId)) {
// UMP devices have protocols that are not PROTOCOL_UNKNOWN // UMP devices have protocols that are not PROTOCOL_UNKNOWN
if (transport == MidiManager.TRANSPORT_UNIVERSAL_MIDI_PACKETS) { if (transport == MidiManager.TRANSPORT_UNIVERSAL_MIDI_PACKETS) {
if (device.getDeviceInfo().getDefaultProtocol() if (device.getDeviceInfo().getDefaultProtocol()
@@ -1029,6 +1091,9 @@ public class MidiService extends IMidiManager.Stub {
if (!device.isUidAllowed(Binder.getCallingUid())) { if (!device.isUidAllowed(Binder.getCallingUid())) {
throw new SecurityException("Attempt to open private device with wrong UID"); throw new SecurityException("Attempt to open private device with wrong UID");
} }
if (!device.isUserIdAllowed(getCallingUserId())) {
throw new SecurityException("Attempt to open virtual device with wrong user id");
}
} }
if (deviceInfo.getType() == MidiDeviceInfo.TYPE_USB) { if (deviceInfo.getType() == MidiDeviceInfo.TYPE_USB) {
@@ -1044,7 +1109,7 @@ public class MidiService extends IMidiManager.Stub {
final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity();
try { try {
Log.i(TAG, "addDeviceConnection() [B] device:" + device); Log.i(TAG, "addDeviceConnection() [B] device:" + device);
client.addDeviceConnection(device, callback); client.addDeviceConnection(device, callback, getCallingUserId());
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
} }
@@ -1106,7 +1171,7 @@ public class MidiService extends IMidiManager.Stub {
final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity();
try { try {
Log.i(TAG, "addDeviceConnection() [C] device:" + device); Log.i(TAG, "addDeviceConnection() [C] device:" + device);
client.addDeviceConnection(device, callback); client.addDeviceConnection(device, callback, getCallingUserId());
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
} }
@@ -1124,6 +1189,7 @@ public class MidiService extends IMidiManager.Stub {
int numOutputPorts, String[] inputPortNames, String[] outputPortNames, int numOutputPorts, String[] inputPortNames, String[] outputPortNames,
Bundle properties, int type, int defaultProtocol) { Bundle properties, int type, int defaultProtocol) {
int uid = Binder.getCallingUid(); int uid = Binder.getCallingUid();
int userId = getCallingUserId();
if (type == MidiDeviceInfo.TYPE_USB && uid != Process.SYSTEM_UID) { if (type == MidiDeviceInfo.TYPE_USB && uid != Process.SYSTEM_UID) {
throw new SecurityException("only system can create USB devices"); throw new SecurityException("only system can create USB devices");
} else if (type == MidiDeviceInfo.TYPE_BLUETOOTH && uid != mBluetoothServiceUid) { } else if (type == MidiDeviceInfo.TYPE_BLUETOOTH && uid != mBluetoothServiceUid) {
@@ -1133,7 +1199,7 @@ public class MidiService extends IMidiManager.Stub {
synchronized (mDevicesByInfo) { synchronized (mDevicesByInfo) {
return addDeviceLocked(type, numInputPorts, numOutputPorts, inputPortNames, return addDeviceLocked(type, numInputPorts, numOutputPorts, inputPortNames,
outputPortNames, properties, server, null, false, uid, outputPortNames, properties, server, null, false, uid,
defaultProtocol); defaultProtocol, userId);
} }
} }
@@ -1210,7 +1276,8 @@ public class MidiService extends IMidiManager.Stub {
private MidiDeviceInfo addDeviceLocked(int type, int numInputPorts, int numOutputPorts, private MidiDeviceInfo addDeviceLocked(int type, int numInputPorts, int numOutputPorts,
String[] inputPortNames, String[] outputPortNames, Bundle properties, String[] inputPortNames, String[] outputPortNames, Bundle properties,
IMidiDeviceServer server, ServiceInfo serviceInfo, IMidiDeviceServer server, ServiceInfo serviceInfo,
boolean isPrivate, int uid, int defaultProtocol) { boolean isPrivate, int uid, int defaultProtocol, int userId) {
Log.d(TAG, "addDeviceLocked()" + uid + " type:" + type);
// Limit the number of devices per app. // Limit the number of devices per app.
int deviceCountForApp = 0; int deviceCountForApp = 0;
@@ -1250,7 +1317,7 @@ public class MidiService extends IMidiManager.Stub {
} }
} }
if (device == null) { if (device == null) {
device = new Device(server, deviceInfo, serviceInfo, uid); device = new Device(server, deviceInfo, serviceInfo, uid, userId);
} }
mDevicesByInfo.put(deviceInfo, device); mDevicesByInfo.put(deviceInfo, device);
if (bluetoothDevice != null) { if (bluetoothDevice != null) {
@@ -1281,12 +1348,14 @@ public class MidiService extends IMidiManager.Stub {
} }
} }
private void addPackageDeviceServers(String packageName) { @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
private void addPackageDeviceServers(String packageName, int userId) {
PackageInfo info; PackageInfo info;
try { try {
info = mPackageManager.getPackageInfo(packageName, info = mPackageManager.getPackageInfoAsUser(packageName,
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); PackageManager.GET_SERVICES | PackageManager.GET_META_DATA
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e); Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
return; return;
@@ -1295,13 +1364,14 @@ public class MidiService extends IMidiManager.Stub {
ServiceInfo[] services = info.services; ServiceInfo[] services = info.services;
if (services == null) return; if (services == null) return;
for (int i = 0; i < services.length; i++) { for (int i = 0; i < services.length; i++) {
addPackageDeviceServer(services[i]); addPackageDeviceServer(services[i], userId);
} }
} }
private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final String[] EMPTY_STRING_ARRAY = new String[0];
private void addPackageDeviceServer(ServiceInfo serviceInfo) { private void addPackageDeviceServer(ServiceInfo serviceInfo, int userId) {
Log.d(TAG, "addPackageDeviceServer()" + userId);
XmlResourceParser parser = null; XmlResourceParser parser = null;
try { try {
@@ -1404,8 +1474,8 @@ public class MidiService extends IMidiManager.Stub {
int uid; int uid;
try { try {
ApplicationInfo appInfo = mPackageManager.getApplicationInfo( ApplicationInfo appInfo = mPackageManager.getApplicationInfoAsUser(
serviceInfo.packageName, 0); serviceInfo.packageName, 0, userId);
uid = appInfo.uid; uid = appInfo.uid;
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "could not fetch ApplicationInfo for " Log.e(TAG, "could not fetch ApplicationInfo for "
@@ -1419,7 +1489,7 @@ public class MidiService extends IMidiManager.Stub {
inputPortNames.toArray(EMPTY_STRING_ARRAY), inputPortNames.toArray(EMPTY_STRING_ARRAY),
outputPortNames.toArray(EMPTY_STRING_ARRAY), outputPortNames.toArray(EMPTY_STRING_ARRAY),
properties, null, serviceInfo, isPrivate, uid, properties, null, serviceInfo, isPrivate, uid,
MidiDeviceInfo.PROTOCOL_UNKNOWN); MidiDeviceInfo.PROTOCOL_UNKNOWN, userId);
} }
// setting properties to null signals that we are no longer // setting properties to null signals that we are no longer
// processing a <device> // processing a <device>
@@ -1437,12 +1507,13 @@ public class MidiService extends IMidiManager.Stub {
} }
} }
private void removePackageDeviceServers(String packageName) { private void removePackageDeviceServers(String packageName, int userId) {
synchronized (mDevicesByInfo) { synchronized (mDevicesByInfo) {
Iterator<Device> iterator = mDevicesByInfo.values().iterator(); Iterator<Device> iterator = mDevicesByInfo.values().iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
Device device = iterator.next(); Device device = iterator.next();
if (packageName.equals(device.getPackageName())) { if (packageName.equals(device.getPackageName())
&& (device.getUserId() == userId)) {
iterator.remove(); iterator.remove();
removeDeviceLocked(device); removeDeviceLocked(device);
} }
@@ -1571,4 +1642,11 @@ public class MidiService extends IMidiManager.Stub {
String extractUsbDeviceTag(String propertyName) { String extractUsbDeviceTag(String propertyName) {
return propertyName.substring(propertyName.length() - MIDI_LEGACY_STRING.length()); return propertyName.substring(propertyName.length() - MIDI_LEGACY_STRING.length());
} }
/**
* @return the user id of the calling user.
*/
private int getCallingUserId() {
return UserHandle.getUserId(Binder.getCallingUid());
}
} }