From 5ff9e2a1719f78cddc7a23d6572ab15ab595dafd Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Mon, 9 Mar 2015 12:00:20 -0700 Subject: [PATCH] MidiManager: Add MIDI device status notifications MidiManager clients can be notified of device status changes via a new MidiDeviceStatus object. MidiDeviceStatus contains the busy status of the device's input ports and number of connections to the output ports. MidiDeviceService now has an optional callback for receiving notifications when its ports change as well. Change-Id: I1600df4464d82724bc026c27b9633ae9c412d3f0 --- .../media/midi/IMidiDeviceListener.aidl | 2 + .../java/android/media/midi/IMidiManager.aidl | 8 + .../android/media/midi/MidiDeviceServer.java | 72 ++++++++- .../android/media/midi/MidiDeviceService.java | 16 +- .../android/media/midi/MidiDeviceStatus.aidl | 19 +++ .../android/media/midi/MidiDeviceStatus.java | 141 ++++++++++++++++++ .../android/media/midi/MidiDispatcher.java | 8 +- .../java/android/media/midi/MidiManager.java | 36 ++++- .../java/com/android/server/MidiService.java | 105 +++++++++++-- .../com/android/server/usb/UsbMidiDevice.java | 2 +- 10 files changed, 380 insertions(+), 29 deletions(-) create mode 100644 media/java/android/media/midi/MidiDeviceStatus.aidl create mode 100644 media/java/android/media/midi/MidiDeviceStatus.java diff --git a/media/java/android/media/midi/IMidiDeviceListener.aidl b/media/java/android/media/midi/IMidiDeviceListener.aidl index 17d9bfd9573c9..31c66e3f8250b 100644 --- a/media/java/android/media/midi/IMidiDeviceListener.aidl +++ b/media/java/android/media/midi/IMidiDeviceListener.aidl @@ -17,10 +17,12 @@ package android.media.midi; import android.media.midi.MidiDeviceInfo; +import android.media.midi.MidiDeviceStatus; /** @hide */ oneway interface IMidiDeviceListener { void onDeviceAdded(in MidiDeviceInfo device); void onDeviceRemoved(in MidiDeviceInfo device); + void onDeviceStatusChanged(in MidiDeviceStatus status); } diff --git a/media/java/android/media/midi/IMidiManager.aidl b/media/java/android/media/midi/IMidiManager.aidl index 617b03e704486..a3b40d68b73ea 100644 --- a/media/java/android/media/midi/IMidiManager.aidl +++ b/media/java/android/media/midi/IMidiManager.aidl @@ -19,6 +19,7 @@ package android.media.midi; import android.media.midi.IMidiDeviceListener; import android.media.midi.IMidiDeviceServer; import android.media.midi.MidiDeviceInfo; +import android.media.midi.MidiDeviceStatus; import android.os.Bundle; import android.os.IBinder; @@ -44,4 +45,11 @@ interface IMidiManager // used by MidiDeviceService to access the MidiDeviceInfo that was created based on its // manifest's meta-data MidiDeviceInfo getServiceDeviceInfo(String packageName, String className); + + // used for client's to retrieve a device's MidiDeviceStatus + MidiDeviceStatus getDeviceStatus(in MidiDeviceInfo deviceInfo); + + // used by MIDI devices to report their status + // the token is used by MidiService for death notification + void setDeviceStatus(IBinder token, in MidiDeviceStatus status); } diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java index 6531052a56100..b3c0e3a485963 100644 --- a/media/java/android/media/midi/MidiDeviceServer.java +++ b/media/java/android/media/midi/MidiDeviceServer.java @@ -16,8 +16,8 @@ package android.media.midi; -import android.os.IBinder; import android.os.Binder; +import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; @@ -61,7 +61,25 @@ public final class MidiDeviceServer implements Closeable { private final CopyOnWriteArrayList mInputPorts = new CopyOnWriteArrayList(); + + // for reporting device status + private final IBinder mDeviceStatusToken = new Binder(); + private final boolean[] mInputPortBusy; + private final int[] mOutputPortOpenCount; + private final CloseGuard mGuard = CloseGuard.get(); + private boolean mIsClosed; + + private final Callback mCallback; + + public interface Callback { + /** + * Called to notify when an our device status has changed + * @param server the {@link MidiDeviceServer} that changed + * @param status the {@link MidiDeviceStatus} for the device + */ + public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status); + } abstract private class PortClient implements IBinder.DeathRecipient { final IBinder mToken; @@ -96,7 +114,10 @@ public final class MidiDeviceServer implements Closeable { void close() { mToken.unlinkToDeath(this, 0); synchronized (mInputPortOutputPorts) { - mInputPortOutputPorts[mOutputPort.getPortNumber()] = null; + int portNumber = mOutputPort.getPortNumber(); + mInputPortOutputPorts[portNumber] = null; + mInputPortBusy[portNumber] = false; + updateDeviceStatus(); } IoUtils.closeQuietly(mOutputPort); } @@ -113,7 +134,15 @@ public final class MidiDeviceServer implements Closeable { @Override void close() { mToken.unlinkToDeath(this, 0); - mOutputPortDispatchers[mInputPort.getPortNumber()].getSender().disconnect(mInputPort); + int portNumber = mInputPort.getPortNumber(); + MidiDispatcher dispatcher = mOutputPortDispatchers[portNumber]; + synchronized (dispatcher) { + dispatcher.getSender().disconnect(mInputPort); + int openCount = dispatcher.getReceiverCount(); + mOutputPortOpenCount[portNumber] = openCount; + updateDeviceStatus(); + } + mInputPorts.remove(mInputPort); IoUtils.closeQuietly(mInputPort); } @@ -153,6 +182,8 @@ public final class MidiDeviceServer implements Closeable { synchronized (mPortClients) { mPortClients.put(token, client); } + mInputPortBusy[portNumber] = true; + updateDeviceStatus(); return pair[1]; } catch (IOException e) { Log.e(TAG, "unable to create ParcelFileDescriptors in openInputPort"); @@ -178,7 +209,14 @@ public final class MidiDeviceServer implements Closeable { ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair( OsConstants.SOCK_SEQPACKET); MidiInputPort inputPort = new MidiInputPort(pair[0], portNumber); - mOutputPortDispatchers[portNumber].getSender().connect(inputPort); + MidiDispatcher dispatcher = mOutputPortDispatchers[portNumber]; + synchronized (dispatcher) { + dispatcher.getSender().connect(inputPort); + int openCount = dispatcher.getReceiverCount(); + mOutputPortOpenCount[portNumber] = openCount; + updateDeviceStatus(); + } + mInputPorts.add(inputPort); OutputPortClient client = new OutputPortClient(token, inputPort); synchronized (mPortClients) { @@ -215,11 +253,12 @@ public final class MidiDeviceServer implements Closeable { }; /* package */ MidiDeviceServer(IMidiManager midiManager, MidiReceiver[] inputPortReceivers, - int numOutputPorts) { + int numOutputPorts, Callback callback) { mMidiManager = midiManager; mInputPortReceivers = inputPortReceivers; mInputPortCount = inputPortReceivers.length; mOutputPortCount = numOutputPorts; + mCallback = callback; mInputPortOutputPorts = new MidiOutputPort[mInputPortCount]; @@ -228,6 +267,9 @@ public final class MidiDeviceServer implements Closeable { mOutputPortDispatchers[i] = new MidiDispatcher(); } + mInputPortBusy = new boolean[mInputPortCount]; + mOutputPortOpenCount = new int[numOutputPorts]; + mGuard.open("close"); } @@ -242,9 +284,28 @@ public final class MidiDeviceServer implements Closeable { mDeviceInfo = deviceInfo; } + private void updateDeviceStatus() { + // clear calling identity, since we may be in a Binder call from one of our clients + long identityToken = Binder.clearCallingIdentity(); + + MidiDeviceStatus status = new MidiDeviceStatus(mDeviceInfo, mInputPortBusy, + mOutputPortOpenCount); + if (mCallback != null) { + mCallback.onDeviceStatusChanged(this, status); + } + try { + mMidiManager.setDeviceStatus(mDeviceStatusToken, status); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in updateDeviceStatus"); + } finally { + Binder.restoreCallingIdentity(identityToken); + } + } + @Override public void close() throws IOException { synchronized (mGuard) { + if (mIsClosed) return; mGuard.close(); for (int i = 0; i < mInputPortCount; i++) { @@ -263,6 +324,7 @@ public final class MidiDeviceServer implements Closeable { } catch (RemoteException e) { Log.e(TAG, "RemoteException in unregisterDeviceServer"); } + mIsClosed = true; } } diff --git a/media/java/android/media/midi/MidiDeviceService.java b/media/java/android/media/midi/MidiDeviceService.java index 64f69cdcd1320..5f55ae2963c15 100644 --- a/media/java/android/media/midi/MidiDeviceService.java +++ b/media/java/android/media/midi/MidiDeviceService.java @@ -57,6 +57,13 @@ abstract public class MidiDeviceService extends Service { private MidiDeviceServer mServer; private MidiDeviceInfo mDeviceInfo; + private final MidiDeviceServer.Callback mCallback = new MidiDeviceServer.Callback() { + @Override + public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status) { + MidiDeviceService.this.onDeviceStatusChanged(status); + } + }; + @Override public void onCreate() { mMidiManager = IMidiManager.Stub.asInterface( @@ -75,7 +82,7 @@ abstract public class MidiDeviceService extends Service { inputPortReceivers = new MidiReceiver[0]; } server = new MidiDeviceServer(mMidiManager, inputPortReceivers, - deviceInfo.getOutputPortCount()); + deviceInfo.getOutputPortCount(), mCallback); server.setDeviceInfo(deviceInfo); } catch (RemoteException e) { Log.e(TAG, "RemoteException in IMidiManager.getServiceDeviceInfo"); @@ -114,6 +121,13 @@ abstract public class MidiDeviceService extends Service { return mDeviceInfo; } + /** + * Called to notify when an our {@link MidiDeviceStatus} has changed + * @param status the number of the port that was opened + */ + public void onDeviceStatusChanged(MidiDeviceStatus status) { + } + @Override public IBinder onBind(Intent intent) { if (SERVICE_INTERFACE.equals(intent.getAction()) && mServer != null) { diff --git a/media/java/android/media/midi/MidiDeviceStatus.aidl b/media/java/android/media/midi/MidiDeviceStatus.aidl new file mode 100644 index 0000000000000..1a848c0686ad1 --- /dev/null +++ b/media/java/android/media/midi/MidiDeviceStatus.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.midi; + +parcelable MidiDeviceStatus; diff --git a/media/java/android/media/midi/MidiDeviceStatus.java b/media/java/android/media/midi/MidiDeviceStatus.java new file mode 100644 index 0000000000000..cc048896d0a72 --- /dev/null +++ b/media/java/android/media/midi/MidiDeviceStatus.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.midi; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This is an immutable class that describes the current status of a MIDI device's ports. + * + * CANDIDATE FOR PUBLIC API + * @hide + */ +public final class MidiDeviceStatus implements Parcelable { + + private static final String TAG = "MidiDeviceStatus"; + + private final MidiDeviceInfo mDeviceInfo; + // true if input ports are busy + private final boolean mInputPortBusy[]; + // open counts for output ports + private final int mOutputPortOpenCount[]; + + /** + * @hide + */ + public MidiDeviceStatus(MidiDeviceInfo deviceInfo, boolean inputPortBusy[], + int outputPortOpenCount[]) { + // MidiDeviceInfo is immutable so we can share references + mDeviceInfo = deviceInfo; + + // make copies of the arrays + mInputPortBusy = new boolean[inputPortBusy.length]; + System.arraycopy(inputPortBusy, 0, mInputPortBusy, 0, inputPortBusy.length); + mOutputPortOpenCount = new int[outputPortOpenCount.length]; + System.arraycopy(outputPortOpenCount, 0, mOutputPortOpenCount, 0, + outputPortOpenCount.length); + } + + /** + * Creates a MidiDeviceStatus with false for all input port busy values + * and zero for all output port open counts + * @hide + */ + public MidiDeviceStatus(MidiDeviceInfo deviceInfo) { + mDeviceInfo = deviceInfo; + mInputPortBusy = new boolean[deviceInfo.getInputPortCount()]; + mOutputPortOpenCount = new int[deviceInfo.getOutputPortCount()]; + } + + /** + * Returns the {@link MidiDeviceInfo} of the device. + * + * @return the device info + */ + public MidiDeviceInfo getDeviceInfo() { + return mDeviceInfo; + } + + /** + * Returns true if an input port is busy. + * + * @param input port's port number + * @return input port busy status + */ + public boolean isInputPortBusy(int portNumber) { + return mInputPortBusy[portNumber]; + } + + /** + * Returns the open count for an output port. + * + * @param output port's port number + * @return output port open count + */ + public int getOutputPortOpenCount(int portNumber) { + return mOutputPortOpenCount[portNumber]; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(mDeviceInfo.toString()); + int inputPortCount = mDeviceInfo.getInputPortCount(); + int outputPortCount = mDeviceInfo.getOutputPortCount(); + builder.append(" mInputPortBusy=["); + for (int i = 0; i < inputPortCount; i++) { + builder.append(mInputPortBusy[i]); + if (i < inputPortCount -1) { + builder.append(","); + } + } + builder.append("] mOutputPortOpenCount=["); + for (int i = 0; i < outputPortCount; i++) { + builder.append(mOutputPortOpenCount[i]); + if (i < outputPortCount -1) { + builder.append(","); + } + } + builder.append("]"); + return builder.toString(); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public MidiDeviceStatus createFromParcel(Parcel in) { + ClassLoader classLoader = MidiDeviceInfo.class.getClassLoader(); + MidiDeviceInfo deviceInfo = in.readParcelable(classLoader); + boolean[] inputPortBusy = in.createBooleanArray(); + int[] outputPortOpenCount = in.createIntArray(); + return new MidiDeviceStatus(deviceInfo, inputPortBusy, outputPortOpenCount); + } + + public MidiDeviceStatus[] newArray(int size) { + return new MidiDeviceStatus[size]; + } + }; + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeParcelable(mDeviceInfo, flags); + parcel.writeBooleanArray(mInputPortBusy); + parcel.writeIntArray(mOutputPortOpenCount); + } +} diff --git a/media/java/android/media/midi/MidiDispatcher.java b/media/java/android/media/midi/MidiDispatcher.java index 90789e583f454..d13ca74db3707 100644 --- a/media/java/android/media/midi/MidiDispatcher.java +++ b/media/java/android/media/midi/MidiDispatcher.java @@ -55,11 +55,11 @@ public final class MidiDispatcher extends MidiReceiver { }; /** - * Returns whether this dispatcher contains any receivers. - * @return true if the receiver list is not empty + * Returns the number of {@link MidiReceiver}s this dispatcher contains. + * @return the number of receivers */ - public boolean hasReceivers() { - return mReceivers.size() > 0; + public int getReceiverCount() { + return mReceivers.size(); } /** diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java index d7b8c5702bd81..bab906419e25b 100644 --- a/media/java/android/media/midi/MidiManager.java +++ b/media/java/android/media/midi/MidiManager.java @@ -62,6 +62,7 @@ public final class MidiManager { mHandler = handler; } + @Override public void onDeviceAdded(MidiDeviceInfo device) { if (mHandler != null) { final MidiDeviceInfo deviceF = device; @@ -75,6 +76,7 @@ public final class MidiManager { } } + @Override public void onDeviceRemoved(MidiDeviceInfo device) { if (mHandler != null) { final MidiDeviceInfo deviceF = device; @@ -87,25 +89,49 @@ public final class MidiManager { mCallback.onDeviceRemoved(device); } } + + @Override + public void onDeviceStatusChanged(MidiDeviceStatus status) { + if (mHandler != null) { + final MidiDeviceStatus statusF = status; + mHandler.post(new Runnable() { + @Override public void run() { + mCallback.onDeviceStatusChanged(statusF); + } + }); + } else { + mCallback.onDeviceStatusChanged(status); + } + } } /** * Callback class used for clients to receive MIDI device added and removed notifications */ - abstract public static class DeviceCallback { + public static class DeviceCallback { /** * Called to notify when a new MIDI device has been added * * @param device a {@link MidiDeviceInfo} for the newly added device */ - abstract public void onDeviceAdded(MidiDeviceInfo device); + public void onDeviceAdded(MidiDeviceInfo device) { + } /** * Called to notify when a MIDI device has been removed * * @param device a {@link MidiDeviceInfo} for the removed device */ - abstract public void onDeviceRemoved(MidiDeviceInfo device); + public void onDeviceRemoved(MidiDeviceInfo device) { + } + + /** + * Called to notify when the status of a MIDI device has changed + * + * @param device a {@link MidiDeviceStatus} for the changed device + */ + public void onDeviceStatusChanged(MidiDeviceStatus status) { + } } /** @@ -251,10 +277,10 @@ public final class MidiManager { /** @hide */ public MidiDeviceServer createDeviceServer(MidiReceiver[] inputPortReceivers, - int numOutputPorts, Bundle properties, int type) { + int numOutputPorts, Bundle properties, int type, MidiDeviceServer.Callback callback) { try { MidiDeviceServer server = new MidiDeviceServer(mService, inputPortReceivers, - numOutputPorts); + numOutputPorts, callback); MidiDeviceInfo deviceInfo = mService.registerDeviceServer(server.getBinderInterface(), inputPortReceivers.length, numOutputPorts, properties, type); if (deviceInfo == null) { diff --git a/services/core/java/com/android/server/MidiService.java b/services/core/java/com/android/server/MidiService.java index 7f98b300057e7..d534548d1dbc5 100644 --- a/services/core/java/com/android/server/MidiService.java +++ b/services/core/java/com/android/server/MidiService.java @@ -29,6 +29,7 @@ import android.media.midi.IMidiDeviceServer; import android.media.midi.IMidiManager; import android.media.midi.MidiDeviceInfo; import android.media.midi.MidiDeviceService; +import android.media.midi.MidiDeviceStatus; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -147,6 +148,19 @@ public class MidiService extends IMidiManager.Stub { } } + public void deviceStatusChanged(Device device, MidiDeviceStatus status) { + // ignore private devices that our client cannot access + if (!device.isUidAllowed(mUid)) return; + + try { + for (IMidiDeviceListener listener : mListeners) { + listener.onDeviceStatusChanged(status); + } + } catch (RemoteException e) { + Log.e(TAG, "remote exception", e); + } + } + public void binderDied() { removeClient(mToken); } @@ -187,6 +201,8 @@ public class MidiService extends IMidiManager.Stub { private final class Device implements IBinder.DeathRecipient { private final IMidiDeviceServer mServer; private final MidiDeviceInfo mDeviceInfo; + private MidiDeviceStatus mDeviceStatus; + private IBinder mDeviceStatusToken; // ServiceInfo for the device's MidiDeviceServer implementation (virtual devices only) private final ServiceInfo mServiceInfo; // UID of device implementation @@ -204,6 +220,33 @@ public class MidiService extends IMidiManager.Stub { return mDeviceInfo; } + public MidiDeviceStatus getDeviceStatus() { + return mDeviceStatus; + } + + public void setDeviceStatus(IBinder token, MidiDeviceStatus status) { + mDeviceStatus = status; + + if (mDeviceStatusToken == null && token != null) { + // register a death recipient so we can clear the status when the device dies + try { + token.linkToDeath(new IBinder.DeathRecipient() { + @Override + public void binderDied() { + // reset to default status and clear the token + mDeviceStatus = new MidiDeviceStatus(mDeviceInfo); + mDeviceStatusToken = null; + notifyDeviceStatusChanged(Device.this, mDeviceStatus); + } + }, 0); + mDeviceStatusToken = token; + } catch (RemoteException e) { + // reset to default status + mDeviceStatus = new MidiDeviceStatus(mDeviceInfo); + } + } + } + public IMidiDeviceServer getDeviceServer() { return mServer; } @@ -216,6 +259,10 @@ public class MidiService extends IMidiManager.Stub { return (mServiceInfo == null ? null : mServiceInfo.packageName); } + public int getUid() { + return mUid; + } + public boolean isUidAllowed(int uid) { return (!mDeviceInfo.isPrivate() || mUid == uid); } @@ -302,13 +349,14 @@ public class MidiService extends IMidiManager.Stub { @Override public MidiDeviceInfo registerDeviceServer(IMidiDeviceServer server, int numInputPorts, int numOutputPorts, Bundle properties, int type) { - if (type != MidiDeviceInfo.TYPE_VIRTUAL && Binder.getCallingUid() != Process.SYSTEM_UID) { + int uid = Binder.getCallingUid(); + if (type != MidiDeviceInfo.TYPE_VIRTUAL && uid != Process.SYSTEM_UID) { throw new SecurityException("only system can create non-virtual devices"); } synchronized (mDevicesByInfo) { return addDeviceLocked(type, numInputPorts, numOutputPorts, properties, - server, null, false, -1); + server, null, false, uid); } } @@ -337,6 +385,39 @@ public class MidiService extends IMidiManager.Stub { } } + @Override + public MidiDeviceStatus getDeviceStatus(MidiDeviceInfo deviceInfo) { + Device device = mDevicesByInfo.get(deviceInfo); + if (device == null) { + throw new IllegalArgumentException("no such device for " + deviceInfo); + } + return device.getDeviceStatus(); + } + + @Override + public void setDeviceStatus(IBinder token, MidiDeviceStatus status) { + MidiDeviceInfo deviceInfo = status.getDeviceInfo(); + Device device = mDevicesByInfo.get(deviceInfo); + if (device == null) { + // Just return quietly here if device no longer exists + return; + } + if (Binder.getCallingUid() != device.getUid()) { + throw new SecurityException("setDeviceStatus() caller UID " + Binder.getCallingUid() + + " does not match device's UID " + device.getUid()); + } + device.setDeviceStatus(token, status); + notifyDeviceStatusChanged(device, status); + } + + private void notifyDeviceStatusChanged(Device device, MidiDeviceStatus status) { + synchronized (mClients) { + for (Client c : mClients.values()) { + c.deviceStatusChanged(device, status); + } + } + } + // synchronize on mDevicesByInfo private MidiDeviceInfo addDeviceLocked(int type, int numInputPorts, int numOutputPorts, Bundle properties, IMidiDeviceServer server, ServiceInfo serviceInfo, @@ -469,17 +550,15 @@ public class MidiService extends IMidiManager.Stub { continue; } - int uid = -1; - if (isPrivate) { - try { - ApplicationInfo appInfo = mPackageManager.getApplicationInfo( - serviceInfo.packageName, 0); - uid = appInfo.uid; - } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "could not fetch ApplicationInfo for " - + serviceInfo.packageName); - continue; - } + int uid; + try { + ApplicationInfo appInfo = mPackageManager.getApplicationInfo( + serviceInfo.packageName, 0); + uid = appInfo.uid; + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "could not fetch ApplicationInfo for " + + serviceInfo.packageName); + continue; } synchronized (mDevicesByInfo) { diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java index f927965af8863..725f39321eedf 100644 --- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java +++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java @@ -121,7 +121,7 @@ public final class UsbMidiDevice implements Closeable { int outputCount = mOutputStreams.length; mServer = midiManager.createDeviceServer(mInputPortReceivers, outputCount, - properties, MidiDeviceInfo.TYPE_USB); + properties, MidiDeviceInfo.TYPE_USB, null); if (mServer == null) { return false; }