Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 71f672b9 authored by Paul McLean's avatar Paul McLean
Browse files

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

Test: manual

Change-Id: Ic181008427e6e81106d867cc3a70deef8c591841
parent f7683a6f
Loading
Loading
Loading
Loading
+34 −16
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import java.io.Closeable;
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 @@ public final class MidiDevice implements Closeable {
    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 @@ public final class MidiDevice implements Closeable {
     * 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 @@ public final class MidiDevice implements Closeable {
        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);
}
+14 −13
Original line number Diff line number Diff line
@@ -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;
}
+1 −3
Original line number Diff line number Diff line
@@ -4,9 +4,7 @@ include $(CLEAR_VARS)

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) \
+0 −106
Original line number Diff line number Diff line
/*
 * 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
+0 −104
Original line number Diff line number Diff line
/*
 * 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_
Loading