From 2aef7e3559e9e2c78287a00b3f693b6dc19e56f0 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 18 Jun 2015 10:05:17 -0700 Subject: Fix MidiDevice.MidiConnection lifecycle Update device server's MidiDeviceStatus when a connection is made to one of its output ports. After connecting an input port to an output port using MidiDevice.connectPorts(), do not call IMidiDeviceServer.closePort() until MidiDevice.MidiConnection.close() is called. While I was in there, added missing CloseGuard support to the MidiDevice.MidiConnection class. This fixes a problem resulting in UsbMidiDevice closing the device's ALSA driver too soon. Bug: 21850709 Change-Id: I0c120f76b42eec8a143161e46dba73fbec5e4f31 --- media/java/android/media/midi/MidiDevice.java | 42 ++++++++++++++++------ .../java/android/media/midi/MidiDeviceServer.java | 9 ++++- media/java/android/media/midi/MidiInputPort.java | 22 ++++++++++-- 3 files changed, 59 insertions(+), 14 deletions(-) (limited to 'media') diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java index 7998a92..93fb6d2 100644 --- a/media/java/android/media/midi/MidiDevice.java +++ b/media/java/android/media/midi/MidiDevice.java @@ -50,21 +50,43 @@ public final class MidiDevice implements Closeable { * Close this object to terminate the connection. */ public class MidiConnection implements Closeable { - private final IBinder mToken; - private final MidiInputPort mInputPort; - - MidiConnection(IBinder token, MidiInputPort inputPort) { - mToken = token; - mInputPort = inputPort; + private final IMidiDeviceServer mInputPortDeviceServer; + private final IBinder mInputPortToken; + private final IBinder mOutputPortToken; + private final CloseGuard mGuard = CloseGuard.get(); + private boolean mIsClosed; + + MidiConnection(IBinder outputPortToken, MidiInputPort inputPort) { + mInputPortDeviceServer = inputPort.getDeviceServer(); + mInputPortToken = inputPort.getToken(); + mOutputPortToken = outputPortToken; + mGuard.open("close"); } @Override public void close() throws IOException { + synchronized (mGuard) { + if (mIsClosed) return; + mGuard.close(); + try { + // close input port + mInputPortDeviceServer.closePort(mInputPortToken); + // close output port + mDeviceServer.closePort(mOutputPortToken); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in MidiConnection.close"); + } + mIsClosed = true; + } + } + + @Override + protected void finalize() throws Throwable { try { - mDeviceServer.closePort(mToken); - IoUtils.closeQuietly(mInputPort); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException in MidiConnection.close"); + mGuard.warnIfOpen(); + close(); + } finally { + super.finalize(); } } } diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java index 1212b64..19ff624 100644 --- a/media/java/android/media/midi/MidiDeviceServer.java +++ b/media/java/android/media/midi/MidiDeviceServer.java @@ -257,7 +257,14 @@ public final class MidiDeviceServer implements Closeable { public void connectPorts(IBinder token, ParcelFileDescriptor pfd, int outputPortNumber) { MidiInputPort inputPort = new MidiInputPort(pfd, outputPortNumber); - mOutputPortDispatchers[outputPortNumber].getSender().connect(inputPort); + MidiDispatcher dispatcher = mOutputPortDispatchers[outputPortNumber]; + synchronized (dispatcher) { + dispatcher.getSender().connect(inputPort); + int openCount = dispatcher.getReceiverCount(); + mOutputPortOpenCount[outputPortNumber] = openCount; + updateDeviceStatus(); + } + mInputPorts.add(inputPort); OutputPortClient client = new OutputPortClient(token, inputPort); synchronized (mPortClients) { diff --git a/media/java/android/media/midi/MidiInputPort.java b/media/java/android/media/midi/MidiInputPort.java index af5a86c..db41b10 100644 --- a/media/java/android/media/midi/MidiInputPort.java +++ b/media/java/android/media/midi/MidiInputPort.java @@ -103,17 +103,33 @@ public final class MidiInputPort extends MidiReceiver implements Closeable { // used by MidiDevice.connectInputPort() to connect our socket directly to another device /* package */ ParcelFileDescriptor claimFileDescriptor() { - synchronized (mBuffer) { - ParcelFileDescriptor pfd = mParcelFileDescriptor; - if (pfd != null) { + synchronized (mGuard) { + ParcelFileDescriptor pfd; + synchronized (mBuffer) { + pfd = mParcelFileDescriptor; + if (pfd == null) return null; IoUtils.closeQuietly(mOutputStream); mParcelFileDescriptor = null; mOutputStream = null; } + + // Set mIsClosed = true so we will not call mDeviceServer.closePort() in close(). + // MidiDevice.MidiConnection.close() will do the cleanup instead. + mIsClosed = true; return pfd; } } + // used by MidiDevice.MidiConnection to close this port after the connection is closed + /* package */ IBinder getToken() { + return mToken; + } + + // used by MidiDevice.MidiConnection to close this port after the connection is closed + /* package */ IMidiDeviceServer getDeviceServer() { + return mDeviceServer; + } + @Override public void close() throws IOException { synchronized (mGuard) { -- cgit v1.1