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

Commit b8feaa5e authored by Paul Mclean's avatar Paul Mclean Committed by Android (Google) Code Review
Browse files

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

parents c51d55ea 71f672b9
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