Switching Native MIDI API to an "opaque pointers" model.

Test: manual

Change-Id: Ic181008427e6e81106d867cc3a70deef8c591841
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index 4b43260..f7dd0b3 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -30,6 +30,8 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 
+import java.util.HashSet;
+
 /**
  * This class is used for sending and receiving data to and from a MIDI device
  * Instances of this class are created by {@link MidiManager#openDevice}.
@@ -47,7 +49,18 @@
     private final IBinder mClientToken;
     private final IBinder mDeviceToken;
     private boolean mIsDeviceClosed;
-    private boolean mIsMirroredToNative;
+
+    // Native API Helpers
+    /**
+     * Keep a static list of MidiDevice objects that are mirrorToNative()'d so they
+     * don't get inadvertantly garbage collected.
+     */
+    private static HashSet<MidiDevice> mMirroredDevices = new HashSet<MidiDevice>();
+
+    /**
+     * If this device is mirrorToNatived(), this is the native device handler.
+     */
+    private long mNativeHandle;
 
     private final CloseGuard mGuard = CloseGuard.get();
 
@@ -218,34 +231,39 @@
      * Makes Midi Device available to the Native API
      * @hide
      */
-    public void mirrorToNative() throws IOException {
-        if (mIsDeviceClosed || mIsMirroredToNative) {
-            return;
+    public long mirrorToNative() throws IOException {
+        if (mIsDeviceClosed || mNativeHandle != 0) {
+            return 0;
         }
 
-        int result = mirrorToNative(mDeviceServer.asBinder(), mDeviceInfo.getId());
-        if (result != 0) {
-            throw new IOException("Failed mirroring to native: " + result);
+        mNativeHandle = native_mirrorToNative(mDeviceServer.asBinder(), mDeviceInfo.getId());
+        if (mNativeHandle == 0) {
+            throw new IOException("Failed mirroring to native");
         }
 
-        mIsMirroredToNative = true;
+        synchronized (mMirroredDevices) {
+            mMirroredDevices.add(this);
+        }
+        return mNativeHandle;
     }
 
     /**
      * Makes Midi Device no longer available to the Native API
      * @hide
      */
-    public void removeFromNative() throws IOException {
-        if (!mIsMirroredToNative) {
+    public void removeFromNative() {
+        if (mNativeHandle == 0) {
             return;
         }
 
-        int result = removeFromNative(mDeviceInfo.getId());
-        if (result != 0) {
-            throw new IOException("Failed removing from native: " + result);
+        synchronized (mGuard) {
+            native_removeFromNative(mNativeHandle);
+            mNativeHandle = 0;
         }
 
-        mIsMirroredToNative = false;
+        synchronized (mMirroredDevices) {
+            mMirroredDevices.remove(this);
+        }
     }
 
     @Override
@@ -279,6 +297,6 @@
         return ("MidiDevice: " + mDeviceInfo.toString());
     }
 
-    private native int mirrorToNative(IBinder deviceServerBinder, int uid);
-    private native int removeFromNative(int uid);
+    private native long native_mirrorToNative(IBinder deviceServerBinder, int id);
+    private native void native_removeFromNative(long deviceHandle);
 }
diff --git a/media/jni/midi/android_media_midi_MidiDevice.cpp b/media/jni/midi/android_media_midi_MidiDevice.cpp
index 1e54bac..3743e4a 100644
--- a/media/jni/midi/android_media_midi_MidiDevice.cpp
+++ b/media/jni/midi/android_media_midi_MidiDevice.cpp
@@ -18,32 +18,33 @@
 #define LOG_TAG "Midi-JNI"
 
 #include <android_util_Binder.h>
-#include <midi/MidiDeviceRegistry.h>
+#include <midi/midi_internal.h>
 #include <nativehelper/jni.h>
 #include <utils/Log.h>
 
 using namespace android;
 using namespace android::media::midi;
 
-extern "C" jint Java_android_media_midi_MidiDevice_mirrorToNative(
-        JNIEnv *env, jobject thiz, jobject midiDeviceServer, jint id)
+extern "C" jlong Java_android_media_midi_MidiDevice_native_1mirrorToNative(
+        JNIEnv *env, jobject, jobject midiDeviceServer, jint id)
 {
-    (void)thiz;
+    // ALOGI("native_mirrorToNative(%p)...", midiDeviceServer);
     sp<IBinder> serverBinder = ibinderForJavaObject(env, midiDeviceServer);
     if (serverBinder.get() == NULL) {
         ALOGE("Could not obtain IBinder from passed jobject");
         return -EINVAL;
     }
-    // return MidiDeviceManager::getInstance().addDevice(serverBinder, uid);
-    return MidiDeviceRegistry::getInstance().addDevice(
-               new BpMidiDeviceServer(serverBinder), id);
+
+    AMIDI_Device* devicePtr = new AMIDI_Device;
+    devicePtr->server = new BpMidiDeviceServer(serverBinder);
+    devicePtr->deviceId = id;
+
+    return (jlong)devicePtr;
 }
 
-extern "C" jint Java_android_media_midi_MidiDevice_removeFromNative(
-        JNIEnv *env, jobject thiz, jint uid)
+extern "C" void Java_android_media_midi_MidiDevice_native_removeFromNative(
+        JNIEnv *, jobject , jlong nativeToken)
 {
-    (void)env;
-    (void)thiz;
-    // return MidiDeviceManager::getInstance().removeDevice(uid);
-    return MidiDeviceRegistry::getInstance().removeDevice(uid);
+    AMIDI_Device* devicePtr = (AMIDI_Device*)nativeToken;
+    delete devicePtr;
 }
diff --git a/media/native/midi/Android.mk b/media/native/midi/Android.mk
index b91c430..dbc5eed 100644
--- a/media/native/midi/Android.mk
+++ b/media/native/midi/Android.mk
@@ -4,9 +4,7 @@
 
 LOCAL_SRC_FILES := \
 	../../java/android/media/midi/IMidiDeviceServer.aidl \
-	midi.cpp \
-	MidiDeviceRegistry.cpp \
-	MidiPortRegistry.cpp
+	midi.cpp
 
 LOCAL_AIDL_INCLUDES := \
 	$(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
diff --git a/media/native/midi/MidiDeviceRegistry.cpp b/media/native/midi/MidiDeviceRegistry.cpp
deleted file mode 100644
index 8854a08..0000000
--- a/media/native/midi/MidiDeviceRegistry.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include "MidiDeviceRegistry.h"
-
-namespace android {
-
-ANDROID_SINGLETON_STATIC_INSTANCE(media::midi::MidiDeviceRegistry);
-
-namespace media {
-namespace midi {
-
-MidiDeviceRegistry::MidiDeviceRegistry() : mNextDeviceToken(1) {
-}
-
-status_t MidiDeviceRegistry::addDevice(sp<BpMidiDeviceServer> server, int32_t deviceId) {
-    if (server.get() == nullptr) {
-        return -EINVAL;
-    }
-
-    std::lock_guard<std::mutex> guard(mMapsLock);
-    mServers[deviceId] = server;
-    return OK;
-}
-
-status_t MidiDeviceRegistry::removeDevice(int32_t deviceId) {
-    std::lock_guard<std::mutex> guard(mMapsLock);
-    mServers.erase(deviceId);
-    const auto& iter = mUidToToken.find(deviceId);
-    if (iter != mUidToToken.end()) {
-        mTokenToUid.erase(iter->second);
-        mUidToToken.erase(iter);
-    }
-    return OK;
-}
-
-//NOTE: This creates an entry if not found, or returns an existing one.
-status_t MidiDeviceRegistry::obtainDeviceToken(int32_t deviceId, AMIDI_Device *deviceTokenPtr) {
-    std::lock_guard<std::mutex> guard(mMapsLock);
-    const auto& serversIter = mServers.find(deviceId);
-    if (serversIter == mServers.end()) {
-        // Not found.
-        return -EINVAL;
-    }
-
-    const auto& iter = mUidToToken.find(deviceId);
-    if (iter != mUidToToken.end()) {
-        *deviceTokenPtr = iter->second;
-    } else {
-        *deviceTokenPtr = mNextDeviceToken++;
-        mTokenToUid[*deviceTokenPtr] = deviceId;
-        mUidToToken[deviceId] = *deviceTokenPtr;
-    }
-    return OK;
-}
-
-status_t MidiDeviceRegistry::releaseDevice(AMIDI_Device deviceToken) {
-    std::lock_guard<std::mutex> guard(mMapsLock);
-    const auto& iter = mTokenToUid.find(deviceToken);
-    if (iter == mTokenToUid.end()) {
-        // Not found
-        return -EINVAL;
-    }
-
-    mServers.erase(iter->second);
-    mUidToToken.erase(iter->second);
-    mTokenToUid.erase(iter);
-    return OK;
-}
-
-status_t MidiDeviceRegistry::getDeviceByToken(
-        AMIDI_Device deviceToken, sp<BpMidiDeviceServer> *devicePtr) {
-    std::lock_guard<std::mutex> guard(mMapsLock);
-    int32_t id = -1;
-    {
-        const auto& iter = mTokenToUid.find(deviceToken);
-        if (iter == mTokenToUid.end()) {
-            return -EINVAL;
-        }
-        id = iter->second;
-    }
-    const auto& iter = mServers.find(id);
-    if (iter == mServers.end()) {
-        return -EINVAL;
-    }
-
-    *devicePtr = iter->second;
-    return OK;
-}
-
-} // namespace midi
-} // namespace media
-} // namespace android
diff --git a/media/native/midi/MidiDeviceRegistry.h b/media/native/midi/MidiDeviceRegistry.h
deleted file mode 100644
index 93be733..0000000
--- a/media/native/midi/MidiDeviceRegistry.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef ANDROID_MEDIA_MIDI_DEVICE_REGISTRY_H_
-#define ANDROID_MEDIA_MIDI_DEVICE_REGISTRY_H_
-
-#include <map>
-#include <mutex>
-
-#include <binder/IBinder.h>
-#include <utils/Errors.h>
-#include <utils/Singleton.h>
-
-#include "android/media/midi/BpMidiDeviceServer.h"
-#include "midi.h"
-
-namespace android {
-namespace media {
-namespace midi {
-
-/*
- * Maintains a thread-safe, (singleton) list of MIDI devices with associated Binder interfaces,
- * which are exposed to the Native API via (Java) MidiDevice.mirrorToNative() &
- * MidiDevice.removeFromNative().
- * (Called via MidiDeviceManager::addDevice() MidiManager::removeDevice()).
- */
-class MidiDeviceRegistry : public Singleton<MidiDeviceRegistry> {
-  public:
-    /* Add a MIDI Device to the registry.
-     *
-     * server       The Binder interface to the MIDI device server.
-     * deviceUId    The unique ID of the device obtained from
-     *              the Java API via MidiDeviceInfo.getId().
-     */
-    status_t addDevice(sp<BpMidiDeviceServer> server, int32_t deviceId);
-
-    /* Remove the device (and associated server) from the Device registry.
-     *
-     * deviceUid    The ID of the device which was used in the call to addDevice().
-     */
-    status_t removeDevice(int32_t deviceId);
-
-    /* Gets a device token associated with the device ID. This is used by the
-     * native API to identify/access the device.
-     * Multiple calls without releasing the token will return the same value.
-     *
-     * deviceUid    The ID of the device.
-     * deviceTokenPtr Receives the device (native) token associated with the device ID.
-     * returns: OK on success, error code otherwise.
-     */
-    status_t obtainDeviceToken(int32_t deviceId, AMIDI_Device *deviceTokenPtr);
-
-    /*
-     * Releases the native API device token associated with a MIDI device.
-     *
-     * deviceToken The device (native) token associated with the device ID.
-     */
-    status_t releaseDevice(AMIDI_Device deviceToken);
-
-    /*
-     * Gets the Device server binder interface associated with the device token.
-     *
-     * deviceToken The device (native) token associated with the device ID.
-     */
-    status_t getDeviceByToken(AMIDI_Device deviceToken, sp<BpMidiDeviceServer> *devicePtr);
-
-  private:
-    friend class Singleton<MidiDeviceRegistry>;
-    MidiDeviceRegistry();
-
-    // Access Mutex
-    std::mutex                              mMapsLock;
-
-    // maps device IDs to servers
-    std::map<int32_t, sp<BpMidiDeviceServer>>   mServers;
-
-    // maps device tokens to device ID
-    std::map<AMIDI_Device, int32_t>         mTokenToUid;
-
-    // maps device IDs to device tokens
-    std::map<int32_t, AMIDI_Device>         mUidToToken;
-
-    // Value of next device token to dole out.
-    AMIDI_Device                            mNextDeviceToken;
-};
-
-} // namespace midi
-} // namespace media
-} // namespace android
-
-#endif // ANDROID_MEDIA_MIDI_DEVICE_REGISTRY_H_
diff --git a/media/native/midi/MidiPortRegistry.cpp b/media/native/midi/MidiPortRegistry.cpp
deleted file mode 100644
index fa70af8..0000000
--- a/media/native/midi/MidiPortRegistry.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include "MidiPortRegistry.h"
-
-namespace android {
-
-ANDROID_SINGLETON_STATIC_INSTANCE(media::midi::MidiPortRegistry);
-
-namespace media {
-namespace midi {
-
-//TODO Note that these 2 are identical
-struct MidiPortRegistry::OutputPort {
-    AMIDI_Device device;
-    sp<IBinder> binderToken;
-    base::unique_fd ufd;
-};
-
-struct MidiPortRegistry::InputPort {
-    AMIDI_Device device;
-    sp<IBinder> binderToken;
-    base::unique_fd ufd;
-};
-
-MidiPortRegistry::MidiPortRegistry() : mNextOutputPortToken(0), mNextInputPortToken(0) {
-}
-
-status_t MidiPortRegistry::addOutputPort(
-        AMIDI_Device device,
-        sp<IBinder> portToken,
-        base::unique_fd &&ufd,
-        AMIDI_OutputPort *portPtr) {
-    *portPtr = mNextOutputPortToken++;
-
-    OutputPortEntry* portEntry = new OutputPortEntry;
-    portEntry->port = new OutputPort;
-    portEntry->state = MIDI_OUTPUT_PORT_STATE_OPEN_IDLE;
-    portEntry->port = new OutputPort;
-    portEntry->port->device = device;
-    portEntry->port->binderToken = portToken;
-    portEntry->port->ufd = std::move(ufd);
-
-    mOutputPortMap[*portPtr] = portEntry;
-
-    return OK;
-}
-
-status_t MidiPortRegistry::removeOutputPort(
-        AMIDI_OutputPort port,
-        AMIDI_Device *devicePtr,
-        sp<IBinder> *portTokenPtr) {
-    OutputPortMap::iterator itr = mOutputPortMap.find(port);
-    if (itr == mOutputPortMap.end()) {
-        return -EINVAL;
-    }
-
-    OutputPortEntry *entry = mOutputPortMap[port];
-    int portState = MIDI_OUTPUT_PORT_STATE_OPEN_IDLE;
-    while (!entry->state.compare_exchange_weak(portState, MIDI_OUTPUT_PORT_STATE_CLOSED)) {
-        if (portState == MIDI_OUTPUT_PORT_STATE_CLOSED) {
-            return -EINVAL; // Already closed
-        }
-    }
-    *devicePtr = entry->port->device;
-    *portTokenPtr = entry->port->binderToken;
-    delete entry->port;
-    entry->port = nullptr;
-
-    mOutputPortMap.erase(itr);
-
-    return OK;
-}
-
-status_t MidiPortRegistry::getOutputPortFdAndLock(
-        AMIDI_OutputPort port, base::unique_fd **ufdPtr) {
-    if (mOutputPortMap.find(port) == mOutputPortMap.end()) {
-        return -EINVAL;
-    }
-
-    OutputPortEntry *entry = mOutputPortMap[port];
-    int portState = MIDI_OUTPUT_PORT_STATE_OPEN_IDLE;
-    if (!entry->state.compare_exchange_strong(portState, MIDI_OUTPUT_PORT_STATE_OPEN_ACTIVE)) {
-        // The port has been closed.
-        return -EPIPE;
-    }
-    *ufdPtr = &entry->port->ufd;
-
-    return OK;
-}
-
-status_t MidiPortRegistry::unlockOutputPort(AMIDI_OutputPort port) {
-    if (mOutputPortMap.find(port) == mOutputPortMap.end()) {
-        return -EINVAL;
-    }
-
-    OutputPortEntry *entry = mOutputPortMap[port];
-    entry->state.store(MIDI_OUTPUT_PORT_STATE_OPEN_IDLE);
-    return OK;
-}
-
-status_t MidiPortRegistry::addInputPort(
-        AMIDI_Device device,
-        sp<IBinder> portToken,
-        base::unique_fd &&ufd,
-        AMIDI_InputPort *portPtr) {
-    *portPtr = mNextInputPortToken++;
-
-    InputPortEntry *entry = new InputPortEntry;
-
-    entry->state = MIDI_INPUT_PORT_STATE_OPEN_IDLE;
-    entry->port = new InputPort;
-    entry->port->device = device;
-    entry->port->binderToken = portToken;
-    entry->port->ufd = std::move(ufd);
-
-    mInputPortMap[*portPtr] = entry;
-
-    return OK;
-}
-
-status_t MidiPortRegistry::removeInputPort(
-        AMIDI_InputPort port,
-        AMIDI_Device *devicePtr,
-        sp<IBinder> *portTokenPtr) {
-    InputPortMap::iterator itr = mInputPortMap.find(port);
-    if (itr == mInputPortMap.end()) {
-        return -EINVAL;
-    }
-
-    InputPortEntry *entry = mInputPortMap[port];
-    int portState = MIDI_INPUT_PORT_STATE_OPEN_IDLE;
-    while (!entry->state.compare_exchange_weak(portState, MIDI_INPUT_PORT_STATE_CLOSED)) {
-        if (portState == MIDI_INPUT_PORT_STATE_CLOSED) return -EINVAL; // Already closed
-    }
-
-    *devicePtr = entry->port->device;
-    *portTokenPtr = entry->port->binderToken;
-    delete entry->port;
-    entry->port = nullptr;
-
-    mInputPortMap.erase(itr);
-
-    return OK;
-}
-
-status_t MidiPortRegistry::getInputPortFd(AMIDI_InputPort port, base::unique_fd **ufdPtr) {
-    if (mInputPortMap.find(port) == mInputPortMap.end()) {
-        return -EINVAL;
-    }
-
-    InputPortEntry *entry = mInputPortMap[port];
-
-    *ufdPtr = &entry->port->ufd;
-
-    return OK;
-}
-
-status_t MidiPortRegistry::getInputPortFdAndLock(AMIDI_InputPort port, base::unique_fd **ufdPtr) {
-    if (mInputPortMap.find(port) == mInputPortMap.end()) {
-        return -EINVAL;
-    }
-
-    InputPortEntry *entry = mInputPortMap[port];
-
-    int portState = MIDI_INPUT_PORT_STATE_OPEN_IDLE;
-    if (!entry->state.compare_exchange_strong(portState, MIDI_INPUT_PORT_STATE_OPEN_ACTIVE)) {
-        // The port has been closed.
-        return -EPIPE;
-    }
-    *ufdPtr = &entry->port->ufd;
-    return OK;
-}
-
-status_t MidiPortRegistry::MidiPortRegistry::unlockInputPort(AMIDI_InputPort port) {
-    if (mInputPortMap.find(port) == mInputPortMap.end()) {
-        return -EINVAL;
-    }
-
-    InputPortEntry *entry = mInputPortMap[port];
-    entry->state.store(MIDI_INPUT_PORT_STATE_OPEN_IDLE);
-    return OK;
-}
-
-} // namespace midi
-} // namespace media
-} // namespace android
diff --git a/media/native/midi/MidiPortRegistry.h b/media/native/midi/MidiPortRegistry.h
deleted file mode 100644
index f1ffb78..0000000
--- a/media/native/midi/MidiPortRegistry.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef ANDROID_MEDIA_MIDI_PORT_REGISTRY_H_
-#define ANDROID_MEDIA_MIDI_PORT_REGISTRY_H_
-
-#include <atomic>
-#include <map>
-
-#include <android-base/unique_fd.h>
-#include <binder/IBinder.h>
-#include <utils/Errors.h>
-#include <utils/Singleton.h>
-
-#include "midi.h"
-
-namespace android {
-namespace media {
-namespace midi {
-
-/*
- * Maintains lists of all active input and output MIDI ports and controls access to them. Provides
- * exclusive access to specific MIDI ports.
- */
-class MidiPortRegistry : public Singleton<MidiPortRegistry> {
-  public:
-    /*
-     * Creates an output port entry and associates it with the specified MIDI device.
-     * Called by AMIDI_openOutputPort();
-     *
-     * device       The native API device ID.
-     * portToken    The port token (returned from the device server).
-     * udf          File descriptor for the data port associated with the MIDI output port.
-     * portPtr      Receives the native API port ID of the port being opened.
-     */
-    status_t addOutputPort(
-            AMIDI_Device device,
-            sp<IBinder> portToken,
-            base::unique_fd &&ufd,
-            AMIDI_OutputPort *portPtr);
-
-    /*
-     * Removes for the output port list a previously added output port.
-     * Called by AMIDI_closeOutputPort();
-     *
-     * port         The native API port ID of the port being closed.
-     * devicePtr    Receives the native API device ID associated with the port.
-     * portTokenPtr Receives the binder token associated with the port.
-     */
-    status_t removeOutputPort(
-            AMIDI_OutputPort port,
-            AMIDI_Device *devicePtr,
-            sp<IBinder> *portTokenPtr);
-
-    /*
-     * Creates an input port entry and associates it with the specified MIDI device.
-     * Called by AMIDI_openInputPort();
-     *
-     * device       The native API device ID.
-     * portToken    The port token (returned from the device server).
-     * udf          File descriptor for the data port associated with the MIDI input port.
-     * portPtr      Receives the native API port ID of the port being opened.
-     */
-    status_t addInputPort(
-            AMIDI_Device device,
-            sp<IBinder> portToken,
-            base::unique_fd &&ufd,
-            AMIDI_InputPort *portPtr);
-
-    /*
-     * Removes for the input port list a previously added input port.
-     * Called by AMIDI_closeINputPort();
-     *
-     * port         The native API port ID of the port being closed.
-     * devicePtr    Receives the native API device ID associated with the port.
-     * portTokenPtr Receives the binder token associated with the port.
-     */
-    status_t removeInputPort(
-            AMIDI_InputPort port,
-            AMIDI_Device *devicePtr,
-            sp<IBinder> *portTokenPtr);
-
-    /*
-     * Retrieves an exclusive-access file descriptor for an output port.
-     * Called from AMIDI_receive().
-     *
-     * port     The native API id of the output port.
-     * ufdPtr   Receives the exclusive-access file descriptor for the output port.
-     */
-    status_t getOutputPortFdAndLock(AMIDI_OutputPort port, base::unique_fd **ufdPtr);
-
-    /*
-     * Releases exclusive-access to the port and invalidates the previously received file
-     * descriptor.
-     * Called from AMIDI_receive().
-     *
-     * port The native API id of the output port.
-     */
-    status_t unlockOutputPort(AMIDI_OutputPort port);
-
-    /*
-     * Retrieves an exclusive-access file descriptor for an input port.
-     * (Not being used as (perhaps) AMIDI_sendWithTimestamp() doesn't need exclusive access
-     * to the port).
-     *
-     * port     The native API id of the input port.
-     * ufdPtr   Receives the exclusive-access file descriptor for the input port.
-     */
-    status_t getInputPortFdAndLock(AMIDI_InputPort port, base::unique_fd **ufdPtr);
-
-    /*
-     * Releases exclusive-access to the port and invalidates the previously received file
-     * descriptor.
-     * (Not used. See above).
-     *
-     * port The native API id of the input port.
-     */
-    status_t unlockInputPort(AMIDI_InputPort port);
-
-    /*
-     * Retrieves an unlocked (multi-access) file descriptor for an input port.
-     * Used by AMIDI_sendWith(), AMIDI_sendWithTimestamp & AMIDI_flush.
-     *
-     * port     The native API id of the input port.
-     * ufdPtr   Receives the multi-access file descriptor for the input port.
-     */
-    status_t getInputPortFd(AMIDI_InputPort port, base::unique_fd **ufdPtr);
-
-  private:
-    friend class Singleton<MidiPortRegistry>;
-    MidiPortRegistry();
-
-    /*
-     * Output (data receiving) ports.
-     */
-    struct OutputPort;
-    enum {
-        MIDI_OUTPUT_PORT_STATE_CLOSED = 0,
-        MIDI_OUTPUT_PORT_STATE_OPEN_IDLE,
-        MIDI_OUTPUT_PORT_STATE_OPEN_ACTIVE
-    };
-
-    struct OutputPortEntry {
-        std::atomic_int state;
-        OutputPort *port;
-    };
-
-    typedef std::map<AMIDI_OutputPort, OutputPortEntry*> OutputPortMap;
-    // Access is synchronized per record via 'state' field.
-    std::atomic<AMIDI_OutputPort> mNextOutputPortToken;
-    OutputPortMap  mOutputPortMap;
-
-    /*
-     * Input (data sending) ports.
-     */
-    struct InputPort;
-    enum {
-        MIDI_INPUT_PORT_STATE_CLOSED = 0,
-        MIDI_INPUT_PORT_STATE_OPEN_IDLE,
-        MIDI_INPUT_PORT_STATE_OPEN_ACTIVE
-    };
-
-    struct InputPortEntry {
-        std::atomic_int state;
-        InputPort *port;
-    };
-
-    typedef std::map<AMIDI_OutputPort, InputPortEntry*> InputPortMap;
-    // Access is synchronized per record via 'state' field.
-    std::atomic<AMIDI_InputPort> mNextInputPortToken;
-    InputPortMap  mInputPortMap;
-
-};
-
-} // namespace midi
-} // namespace media
-} // namespace android
-
-#endif // ANDROID_MEDIA_MIDI_PORT_REGISTRY_H_
diff --git a/media/native/midi/midi.cpp b/media/native/midi/midi.cpp
index 1bf0bd0..17b92da3 100644
--- a/media/native/midi/midi.cpp
+++ b/media/native/midi/midi.cpp
@@ -25,10 +25,9 @@
 
 #include "android/media/midi/BpMidiDeviceServer.h"
 #include "media/MidiDeviceInfo.h"
-#include "MidiDeviceRegistry.h"
-#include "MidiPortRegistry.h"
 
 #include "midi.h"
+#include "midi_internal.h"
 
 using android::IBinder;
 using android::BBinder;
@@ -37,13 +36,28 @@
 using android::status_t;
 using android::base::unique_fd;
 using android::binder::Status;
-using android::media::midi::BpMidiDeviceServer;
 using android::media::midi::MidiDeviceInfo;
-using android::media::midi::MidiDeviceRegistry;
-using android::media::midi::MidiPortRegistry;
+
+struct AMIDI_Port {
+    std::atomic_int state;
+    AMIDI_Device    *device;
+    sp<IBinder>     binderToken;
+    unique_fd       ufd;
+};
 
 #define SIZE_MIDIRECEIVEBUFFER AMIDI_BUFFER_SIZE
 
+enum {
+    MIDI_PORT_STATE_CLOSED = 0,
+    MIDI_PORT_STATE_OPEN_IDLE,
+    MIDI_PORT_STATE_OPEN_ACTIVE
+};
+
+enum {
+    PORTTYPE_OUTPUT = 0,
+    PORTTYPE_INPUT = 1
+};
+
 /* TRANSFER PACKET FORMAT (as defined in MidiPortImpl.java)
  *
  * Transfer packet format is as follows (see MidiOutputPort.mThread.run() to see decomposition):
@@ -63,20 +77,12 @@
  *  So 'read()' always returns a whole message.
  */
 
-status_t AMIDI_getDeviceById(int32_t id, AMIDI_Device *devicePtr) {
-    return MidiDeviceRegistry::getInstance().obtainDeviceToken(id, devicePtr);
-}
-
-status_t AMIDI_getDeviceInfo(AMIDI_Device device, AMIDI_DeviceInfo *deviceInfoPtr) {
-    sp<BpMidiDeviceServer> deviceServer;
-    status_t result = MidiDeviceRegistry::getInstance().getDeviceByToken(device, &deviceServer);
-    if (result != OK) {
-        ALOGE("AMIDI_getDeviceInfo bad device token %d: %d", device, result);
-        return result;
-    }
-
+/*
+ * Device Functions
+ */
+status_t AMIDI_getDeviceInfo(AMIDI_Device *device, AMIDI_DeviceInfo *deviceInfoPtr) {
     MidiDeviceInfo deviceInfo;
-    Status txResult = deviceServer->getDeviceInfo(&deviceInfo);
+    Status txResult = device->server->getDeviceInfo(&deviceInfo);
     if (!txResult.isOk()) {
         ALOGE("AMIDI_getDeviceInfo transaction error: %d", txResult.transactionError());
         return txResult.transactionError();
@@ -87,49 +93,74 @@
     deviceInfoPtr->isPrivate = deviceInfo.isPrivate();
     deviceInfoPtr->inputPortCount = deviceInfo.getInputPortNames().size();
     deviceInfoPtr->outputPortCount = deviceInfo.getOutputPortNames().size();
+
+    return OK;
+}
+
+/*
+ * Port Helpers
+ */
+static status_t AMIDI_openPort(AMIDI_Device *device, int portNumber, int type,
+        AMIDI_Port **portPtr) {
+    sp<BBinder> portToken(new BBinder());
+    unique_fd ufd;
+    Status txResult = type == PORTTYPE_OUTPUT
+            ? device->server->openOutputPort(portToken, portNumber, &ufd)
+            : device->server->openInputPort(portToken, portNumber, &ufd);
+    if (!txResult.isOk()) {
+        ALOGE("AMIDI_openPort transaction error: %d", txResult.transactionError());
+        return txResult.transactionError();
+    }
+
+    AMIDI_Port* port = new AMIDI_Port;
+    port->state = MIDI_PORT_STATE_OPEN_IDLE;
+    port->device = device;
+    port->binderToken = portToken;
+    port->ufd = std::move(ufd);
+
+    *portPtr = port;
+
+    return OK;
+}
+
+static status_t AMIDI_closePort(AMIDI_Port *port) {
+    int portState = MIDI_PORT_STATE_OPEN_IDLE;
+    while (!port->state.compare_exchange_weak(portState, MIDI_PORT_STATE_CLOSED)) {
+        if (portState == MIDI_PORT_STATE_CLOSED) {
+            return -EINVAL; // Already closed
+        }
+    }
+
+    Status txResult = port->device->server->closePort(port->binderToken);
+    if (!txResult.isOk()) {
+        return txResult.transactionError();
+    }
+
+    delete port;
+
     return OK;
 }
 
 /*
  * Output (receiving) API
  */
-status_t AMIDI_openOutputPort(AMIDI_Device device, int portNumber, AMIDI_OutputPort *outputPortPtr) {
-    sp<BpMidiDeviceServer> deviceServer;
-    status_t result = MidiDeviceRegistry::getInstance().getDeviceByToken(device, &deviceServer);
-    if (result != OK) {
-        ALOGE("AMIDI_openOutputPort bad device token %d: %d", device, result);
-        return result;
-    }
-
-    sp<BBinder> portToken(new BBinder());
-    unique_fd ufd;
-    Status txResult = deviceServer->openOutputPort(portToken, portNumber, &ufd);
-    if (!txResult.isOk()) {
-        ALOGE("AMIDI_openOutputPort transaction error: %d", txResult.transactionError());
-        return txResult.transactionError();
-    }
-
-    result = MidiPortRegistry::getInstance().addOutputPort(
-            device, portToken, std::move(ufd), outputPortPtr);
-    if (result != OK) {
-        ALOGE("AMIDI_openOutputPort port registration error: %d", result);
-        // Close port
-        return result;
-    }
-    return OK;
+status_t AMIDI_openOutputPort(AMIDI_Device *device, int portNumber,
+        AMIDI_OutputPort **outputPortPtr) {
+    return AMIDI_openPort(device, portNumber, PORTTYPE_OUTPUT, (AMIDI_Port**)outputPortPtr);
 }
 
-ssize_t AMIDI_receive(AMIDI_OutputPort outputPort, AMIDI_Message *messages, ssize_t maxMessages) {
-    unique_fd *ufd;
-    // TODO: May return a nicer self-unlocking object
-    status_t result = MidiPortRegistry::getInstance().getOutputPortFdAndLock(outputPort, &ufd);
-    if (result != OK) {
-        return result;
+ssize_t AMIDI_receive(AMIDI_OutputPort *outputPort, AMIDI_Message *messages, ssize_t maxMessages) {
+    AMIDI_Port *port = (AMIDI_Port*)outputPort;
+    int portState = MIDI_PORT_STATE_OPEN_IDLE;
+    if (!port->state.compare_exchange_strong(portState, MIDI_PORT_STATE_OPEN_ACTIVE)) {
+        // The port has been closed.
+        return -EPIPE;
     }
 
+    status_t result = OK;
     ssize_t messagesRead = 0;
     while (messagesRead < maxMessages) {
-        struct pollfd checkFds[1] = { { *ufd, POLLIN, 0 } };
+        struct pollfd checkFds[1] = { { port->ufd, POLLIN, 0 } };
         int pollResult = poll(checkFds, 1, 0);
         if (pollResult < 1) {
             result = android::INVALID_OPERATION;
@@ -139,7 +170,7 @@
         AMIDI_Message *message = &messages[messagesRead];
         uint8_t readBuffer[AMIDI_PACKET_SIZE];
         memset(readBuffer, 0, sizeof(readBuffer));
-        ssize_t readCount = read(*ufd, readBuffer, sizeof(readBuffer));
+        ssize_t readCount = read(port->ufd, readBuffer, sizeof(readBuffer));
         if (readCount == EINTR) {
             continue;
         }
@@ -157,100 +188,38 @@
             if (dataSize) {
                 memcpy(message->buffer, readBuffer + 1, dataSize);
             }
-            message->timestamp = *(uint64_t*) (readBuffer + readCount - sizeof(uint64_t));
+            message->timestamp = *(uint64_t*)(readBuffer + readCount - sizeof(uint64_t));
         }
         message->len = dataSize;
         ++messagesRead;
     }
 
-    MidiPortRegistry::getInstance().unlockOutputPort(outputPort);
+    port->state.store(MIDI_PORT_STATE_OPEN_IDLE);
+
     return result == OK ? messagesRead : result;
 }
 
-status_t AMIDI_closeOutputPort(AMIDI_OutputPort outputPort) {
-    AMIDI_Device device;
-    sp<IBinder> portToken;
-    status_t result =
-        MidiPortRegistry::getInstance().removeOutputPort(outputPort, &device, &portToken);
-    if (result != OK) {
-        return result;
-    }
-
-    sp<BpMidiDeviceServer> deviceServer;
-    result = MidiDeviceRegistry::getInstance().getDeviceByToken(device, &deviceServer);
-    if (result != OK) {
-        return result;
-    }
-
-    Status txResult = deviceServer->closePort(portToken);
-    if (!txResult.isOk()) {
-        return txResult.transactionError();
-    }
-    return OK;
+status_t AMIDI_closeOutputPort(AMIDI_OutputPort *outputPort) {
+    return AMIDI_closePort((AMIDI_Port*)outputPort);
 }
 
 /*
  * Input (sending) API
  */
-status_t AMIDI_openInputPort(AMIDI_Device device, int portNumber, AMIDI_InputPort *inputPortPtr) {
-    sp<BpMidiDeviceServer> deviceServer;
-    status_t result = MidiDeviceRegistry::getInstance().getDeviceByToken(device, &deviceServer);
-    if (result != OK) {
-        ALOGE("AMIDI_openInputPort bad device token %d: %d", device, result);
-        return result;
-    }
-
-    sp<BBinder> portToken(new BBinder());
-    unique_fd ufd; // this is the file descriptor of the "receive" port s
-    Status txResult = deviceServer->openInputPort(portToken, portNumber, &ufd);
-    if (!txResult.isOk()) {
-        ALOGE("AMIDI_openInputPort transaction error: %d", txResult.transactionError());
-        return txResult.transactionError();
-    }
-
-    result = MidiPortRegistry::getInstance().addInputPort(
-            device, portToken, std::move(ufd), inputPortPtr);
-    if (result != OK) {
-        ALOGE("AMIDI_openInputPort port registration error: %d", result);
-        // Close port
-        return result;
-    }
-
-    return OK;
+status_t AMIDI_openInputPort(AMIDI_Device *device, int portNumber, AMIDI_InputPort **inputPortPtr) {
+    return AMIDI_openPort(device, portNumber, PORTTYPE_INPUT, (AMIDI_Port**)inputPortPtr);
 }
 
-status_t AMIDI_closeInputPort(AMIDI_InputPort inputPort) {
-    AMIDI_Device device;
-    sp<IBinder> portToken;
-    status_t result = MidiPortRegistry::getInstance().removeInputPort(
-            inputPort, &device, &portToken);
-    if (result != OK) {
-        ALOGE("AMIDI_closeInputPort remove port error: %d", result);
-        return result;
-    }
-
-    sp<BpMidiDeviceServer> deviceServer;
-    result = MidiDeviceRegistry::getInstance().getDeviceByToken(device, &deviceServer);
-    if (result != OK) {
-        ALOGE("AMIDI_closeInputPort can't find device error: %d", result);
-        return result;
-    }
-
-    Status txResult = deviceServer->closePort(portToken);
-    if (!txResult.isOk()) {
-        result = txResult.transactionError();
-        ALOGE("AMIDI_closeInputPort transaction error: %d", result);
-        return result;
-    }
-
-    return OK;
+status_t AMIDI_closeInputPort(AMIDI_InputPort *inputPort) {
+    return AMIDI_closePort((AMIDI_Port*)inputPort);
 }
 
-ssize_t AMIDI_getMaxMessageSizeInBytes(AMIDI_InputPort /*inputPort*/) {
+ssize_t AMIDI_getMaxMessageSizeInBytes(AMIDI_InputPort */*inputPort*/) {
     return SIZE_MIDIRECEIVEBUFFER;
 }
 
-static ssize_t AMIDI_makeSendBuffer(uint8_t *buffer, uint8_t *data, ssize_t numBytes, uint64_t timestamp) {
+static ssize_t AMIDI_makeSendBuffer(
+        uint8_t *buffer, uint8_t *data, ssize_t numBytes,uint64_t timestamp) {
     buffer[0] = AMIDI_OPCODE_DATA;
     memcpy(buffer + 1, data, numBytes);
     memcpy(buffer + 1 + numBytes, &timestamp, sizeof(timestamp));
@@ -264,11 +233,11 @@
 //    }
 //}
 
-ssize_t AMIDI_send(AMIDI_InputPort inputPort, uint8_t *buffer, ssize_t numBytes) {
+ssize_t AMIDI_send(AMIDI_InputPort *inputPort, uint8_t *buffer, ssize_t numBytes) {
     return AMIDI_sendWithTimestamp(inputPort, buffer, numBytes, 0);
 }
 
-ssize_t AMIDI_sendWithTimestamp(AMIDI_InputPort inputPort, uint8_t *data,
+ssize_t AMIDI_sendWithTimestamp(AMIDI_InputPort *inputPort, uint8_t *data,
         ssize_t numBytes, int64_t timestamp) {
 
     if (numBytes > SIZE_MIDIRECEIVEBUFFER) {
@@ -277,15 +246,9 @@
 
     // AMIDI_logBuffer(data, numBytes);
 
-    unique_fd *ufd = NULL;
-    status_t result = MidiPortRegistry::getInstance().getInputPortFd(inputPort, &ufd);
-    if (result != OK) {
-        return result;
-    }
-
     uint8_t writeBuffer[SIZE_MIDIRECEIVEBUFFER + AMIDI_PACKET_OVERHEAD];
     ssize_t numTransferBytes = AMIDI_makeSendBuffer(writeBuffer, data, numBytes, timestamp);
-    ssize_t numWritten = write(*ufd, writeBuffer, numTransferBytes);
+    ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, writeBuffer, numTransferBytes);
 
     if (numWritten < numTransferBytes) {
         ALOGE("AMIDI_sendWithTimestamp Couldn't write MIDI data buffer. requested:%zu, written%zu",
@@ -295,16 +258,10 @@
     return numWritten - AMIDI_PACKET_OVERHEAD;
 }
 
-status_t AMIDI_flush(AMIDI_InputPort inputPort) {
-    unique_fd *ufd = NULL;
-    status_t result = MidiPortRegistry::getInstance().getInputPortFd(inputPort, &ufd);
-    if (result != OK) {
-        return result;
-    }
-
+status_t AMIDI_flush(AMIDI_InputPort *inputPort) {
     uint8_t opCode = AMIDI_OPCODE_FLUSH;
     ssize_t numTransferBytes = 1;
-    ssize_t numWritten = write(*ufd, &opCode, numTransferBytes);
+    ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, &opCode, numTransferBytes);
 
     if (numWritten < numTransferBytes) {
         ALOGE("AMIDI_flush Couldn't write MIDI flush. requested:%zu, written%zu",
diff --git a/media/native/midi/midi.h b/media/native/midi/midi.h
index 717bc66..9332b44 100644
--- a/media/native/midi/midi.h
+++ b/media/native/midi/midi.h
@@ -29,22 +29,11 @@
 extern "C" {
 #endif
 
-//typedef struct _AMIDI_Device;
-//typedef struct _AMIDI_InputPort;
-//typedef struct _AMIDI_OutputPort;
-//typedef _AMIDI_Device*      AMIDI_Device;
-//typedef _AMIDI_InputPort*   AMIDI_InputPort;
-//typedef _AMIDI_OutputPort*  AMIDI_OutputPort;
+struct AMIDI_Device;
+struct AMIDI_InputPort;
+struct AMIDI_OutputPort;
 
-typedef int32_t AMIDI_Device;
-typedef int32_t AMIDI_InputPort;
-typedef int32_t  AMIDI_OutputPort;
-
-//TODO - Do we want to wrap this stuff in namespace android { namespace media { namespace midi {?
-
-enum {
-    AMIDI_INVALID_HANDLE = -1
-};
+#define AMIDI_INVALID_HANDLE NULL
 
 enum {
     AMIDI_OPCODE_DATA = 1,
@@ -56,10 +45,10 @@
 };
 
 typedef struct {
-    uint32_t opcode;
-    uint8_t buffer[AMIDI_BUFFER_SIZE];
-    size_t len;
-    int64_t timestamp;
+    uint32_t    opcode;
+    uint8_t     buffer[AMIDI_BUFFER_SIZE];
+    size_t      len;
+    int64_t     timestamp;
 } AMIDI_Message;
 
 enum {
@@ -80,16 +69,6 @@
  * Device API
  */
 /*
- * Retrieves the native API device token for the specified Java API device ID.
- *
- * uid          The Java API id of the device.
- * devicePtr    Receives the associated native API token for the device.
- *
- * Returns OK or a (negative) error code.
- */
-status_t AMIDI_getDeviceById(int32_t id, AMIDI_Device *devicePtr);
-
-/*
  * Retrieves information for the native MIDI device.
  *
  * device           The Native API token for the device.
@@ -97,7 +76,7 @@
  *
  * Returns OK or a (negative) error code.
  */
-status_t AMIDI_getDeviceInfo(AMIDI_Device device, AMIDI_DeviceInfo *deviceInfoPtr);
+status_t AMIDI_getDeviceInfo(AMIDI_Device *device, AMIDI_DeviceInfo *deviceInfoPtr);
 
 /*
  * API for receiving data from the Output port of a device.
@@ -111,7 +90,8 @@
  *
  * Returns OK, or a (negative) error code.
  */
-status_t AMIDI_openOutputPort(AMIDI_Device device, int portNumber, AMIDI_OutputPort *outputPortPtr);
+status_t AMIDI_openOutputPort(AMIDI_Device *device, int portNumber,
+        AMIDI_OutputPort **outputPortPtr);
 
 /*
  * Receives any pending MIDI messages (up to the specified maximum number of messages).
@@ -122,7 +102,7 @@
  *
  * Returns the number of messages received, or a (negative) error code.
  */
-ssize_t AMIDI_receive(AMIDI_OutputPort outputPort, AMIDI_Message *messages, ssize_t maxMessages);
+ssize_t AMIDI_receive(AMIDI_OutputPort *outputPort, AMIDI_Message *messages, ssize_t maxMessages);
 
 /*
  * Closes the output port.
@@ -131,7 +111,7 @@
  *
  * Returns OK, or a (negative) error code.
  */
-status_t AMIDI_closeOutputPort(AMIDI_OutputPort outputPort);
+status_t AMIDI_closeOutputPort(AMIDI_OutputPort *outputPort);
 
 /*
  * API for sending data to the Input port of a device.
@@ -145,12 +125,12 @@
  *
  * Returns OK, or a (negative) error code.
  */
-status_t AMIDI_openInputPort(AMIDI_Device device, int portNumber, AMIDI_InputPort *inputPortPtr);
+status_t AMIDI_openInputPort(AMIDI_Device *device, int portNumber, AMIDI_InputPort **inputPortPtr);
 
 /*
  * Returns the maximum number of bytes that can be received in a single MIDI message.
  */
-ssize_t AMIDI_getMaxMessageSizeInBytes(AMIDI_InputPort inputPort);
+ssize_t AMIDI_getMaxMessageSizeInBytes(AMIDI_InputPort *inputPort);
 
 /*
  * Sends data to the specified input port.
@@ -161,7 +141,7 @@
  *
  * Returns  The number of bytes sent or a (negative) error code.
  */
-ssize_t AMIDI_send(AMIDI_InputPort inputPort, uint8_t *buffer, ssize_t numBytes);
+ssize_t AMIDI_send(AMIDI_InputPort *inputPort, uint8_t *buffer, ssize_t numBytes);
 
 /*
  * Sends data to the specified input port with a timestamp.
@@ -173,7 +153,7 @@
  *
  * Returns  The number of bytes sent or a (negative) error code.
  */
-ssize_t AMIDI_sendWithTimestamp(AMIDI_InputPort inputPort, uint8_t *buffer,
+ssize_t AMIDI_sendWithTimestamp(AMIDI_InputPort *inputPort, uint8_t *buffer,
         ssize_t numBytes, int64_t timestamp);
 
 /*
@@ -183,7 +163,7 @@
  *
  * Returns OK, or a (negative) error code.
  */
-status_t AMIDI_flush(AMIDI_InputPort inputPort);
+status_t AMIDI_flush(AMIDI_InputPort *inputPort);
 
 /*
  * Closes the input port.
@@ -193,7 +173,7 @@
  *
  * Returns OK, or a (negative) error code.
  */
-status_t AMIDI_closeInputPort(AMIDI_InputPort inputPort);
+status_t AMIDI_closeInputPort(AMIDI_InputPort *inputPort);
 
 #ifdef __cplusplus
 }
diff --git a/media/native/midi/midi_internal.h b/media/native/midi/midi_internal.h
new file mode 100644
index 0000000..fd4770e
--- /dev/null
+++ b/media/native/midi/midi_internal.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_MEDIA_MIDI_INTERNAL_H_
+#define ANDROID_MEDIA_MIDI_INTERNAL_H_
+
+#include "android/media/midi/BpMidiDeviceServer.h"
+
+struct AMIDI_Device {
+    android::sp<android::media::midi::BpMidiDeviceServer> server;
+    int32_t deviceId;
+};
+
+#endif // ANDROID_MEDIA_MIDI_INTERNAL_H_
diff --git a/media/tests/NativeMidiDemo/jni/nativemidi-jni.cpp b/media/tests/NativeMidiDemo/jni/nativemidi-jni.cpp
index 8aa874a..0110b75 100644
--- a/media/tests/NativeMidiDemo/jni/nativemidi-jni.cpp
+++ b/media/tests/NativeMidiDemo/jni/nativemidi-jni.cpp
@@ -66,8 +66,8 @@
 
 static std::atomic_ullong sharedCounter;
 
-static AMIDI_Device midiDevice = AMIDI_INVALID_HANDLE;
-static std::atomic<AMIDI_OutputPort> midiOutputPort(AMIDI_INVALID_HANDLE);
+static AMIDI_Device* midiDevice = AMIDI_INVALID_HANDLE;
+static std::atomic<AMIDI_OutputPort*> midiOutputPort(AMIDI_INVALID_HANDLE);
 
 static int setPlaySamples(int newPlaySamples)
 {
@@ -86,7 +86,7 @@
 {
     sharedCounter++;
 
-    AMIDI_OutputPort outputPort = midiOutputPort.load();
+    AMIDI_OutputPort* outputPort = midiOutputPort.load();
     if (outputPort != AMIDI_INVALID_HANDLE) {
         char midiDumpBuffer[1024];
         ssize_t midiReceived = AMIDI_receive(
@@ -235,20 +235,21 @@
 }
 
 void Java_com_example_android_nativemididemo_NativeMidi_startReadingMidi(
-        JNIEnv*, jobject, jint deviceId, jint portNumber) {
+        JNIEnv*, jobject, jlong deviceHandle, jint portNumber) {
     char buffer[1024];
 
-    int result = AMIDI_getDeviceById(deviceId, &midiDevice);
-    if (result == 0) {
-        snprintf(buffer, sizeof(buffer), "Obtained device token for uid %d: token %d", deviceId, midiDevice);
-    } else {
-        snprintf(buffer, sizeof(buffer), "Could not obtain device token for uid %d: %d", deviceId, result);
-    }
+    midiDevice = (AMIDI_Device*)deviceHandle;
+//    int result = AMIDI_getDeviceById(deviceId, &midiDevice);
+//    if (result == 0) {
+//        snprintf(buffer, sizeof(buffer), "Obtained device token for uid %d: token %d", deviceId, midiDevice);
+//    } else {
+//        snprintf(buffer, sizeof(buffer), "Could not obtain device token for uid %d: %d", deviceId, result);
+//    }
     nativemididemo::writeMessage(buffer);
-    if (result) return;
+//    if (result) return;
 
     AMIDI_DeviceInfo deviceInfo;
-    result = AMIDI_getDeviceInfo(midiDevice, &deviceInfo);
+    int result = AMIDI_getDeviceInfo(midiDevice, &deviceInfo);
     if (result == 0) {
         snprintf(buffer, sizeof(buffer), "Device info: uid %d, type %d, priv %d, ports %d I / %d O",
                 deviceInfo.uid, deviceInfo.type, deviceInfo.isPrivate,
@@ -259,27 +260,27 @@
     nativemididemo::writeMessage(buffer);
     if (result) return;
 
-    AMIDI_OutputPort outputPort;
+    AMIDI_OutputPort* outputPort;
     result = AMIDI_openOutputPort(midiDevice, portNumber, &outputPort);
     if (result == 0) {
-        snprintf(buffer, sizeof(buffer), "Opened port %d: token %d", portNumber, outputPort);
+        snprintf(buffer, sizeof(buffer), "Opened port %d: token %p", portNumber, outputPort);
         midiOutputPort.store(outputPort);
     } else {
-        snprintf(buffer, sizeof(buffer), "Could not open port %d: %d", deviceId, result);
+        snprintf(buffer, sizeof(buffer), "Could not open port %p: %d", midiDevice, result);
     }
     nativemididemo::writeMessage(buffer);
 }
 
 void Java_com_example_android_nativemididemo_NativeMidi_stopReadingMidi(
         JNIEnv*, jobject) {
-    AMIDI_OutputPort outputPort = midiOutputPort.exchange(AMIDI_INVALID_HANDLE);
+    AMIDI_OutputPort* outputPort = midiOutputPort.exchange(AMIDI_INVALID_HANDLE);
     if (outputPort == AMIDI_INVALID_HANDLE) return;
     int result = AMIDI_closeOutputPort(outputPort);
     char buffer[1024];
     if (result == 0) {
-        snprintf(buffer, sizeof(buffer), "Closed port by token %d", outputPort);
+        snprintf(buffer, sizeof(buffer), "Closed port by token %p", outputPort);
     } else {
-        snprintf(buffer, sizeof(buffer), "Could not close port by token %d: %d", outputPort, result);
+        snprintf(buffer, sizeof(buffer), "Could not close port by token %p: %d", outputPort, result);
     }
     nativemididemo::writeMessage(buffer);
 }