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

Commit 7fadb5e7 authored by Mike Lockwood's avatar Mike Lockwood Committed by Android Git Automerger
Browse files

am 2b3da7ab: Merge "MTP: Fix race conditions in MtpServer JNI code" into honeycomb

* commit '2b3da7ab':
  MTP: Fix race conditions in MtpServer JNI code
parents 45800cf9 2b3da7ab
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -282,7 +282,7 @@ class MtpPropertyGroup {
    }

    MtpPropertyList getPropertyList(int handle, int format, int depth, int storageID) {
        Log.d(TAG, "getPropertyList handle: " + handle + " format: " + format + " depth: " + depth);
        //Log.d(TAG, "getPropertyList handle: " + handle + " format: " + format + " depth: " + depth);
        if (depth > 1) {
            // we only support depth 0 and 1
            // depth 0: single object, depth 1: immediate children
+0 −4
Original line number Diff line number Diff line
@@ -54,12 +54,8 @@ public class MtpServer {
        native_set_ptp_mode(usePtp);
    }

    // used by the JNI code
    private int mNativeContext;

    private native final void native_setup(MtpDatabase database, String storagePath,
            long reserveSpace);
    private native final void native_finalize();
    private native final void native_start();
    private native final void native_stop();
    private native final void native_send_object_added(int handle);
+41 −69
Original line number Diff line number Diff line
@@ -40,9 +40,6 @@ using namespace android;

// ----------------------------------------------------------------------------

static jfieldID field_context;
static Mutex    sMutex;

// in android_mtp_MtpDatabase.cpp
extern MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database);

@@ -61,96 +58,74 @@ private:
    MtpServer*      mServer;
    String8         mStoragePath;
    uint64_t        mReserveSpace;
    jobject         mJavaServer;
    bool            mDone;
    Mutex           mMutex;
    bool            mUsePtp;
    int             mFd;

public:
    MtpThread(MtpDatabase* database, const char* storagePath, uint64_t reserveSpace,
                jobject javaServer)
    MtpThread(MtpDatabase* database, const char* storagePath, uint64_t reserveSpace)
        :   mDatabase(database),
            mServer(NULL),
            mStoragePath(storagePath),
            mReserveSpace(reserveSpace),
            mJavaServer(javaServer),
            mDone(false),
            mFd(-1)
    {
    }

    void setPtpMode(bool usePtp) {
        sMutex.lock();
        if (mFd >= 0) {
            ioctl(mFd, MTP_SET_INTERFACE_MODE,
                    (usePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP));
        } else {
            int fd = open("/dev/mtp_usb", O_RDWR);
            if (fd >= 0) {
                ioctl(fd, MTP_SET_INTERFACE_MODE,
                        (usePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP));
                close(fd);
            }
        }
        sMutex.unlock();
        mMutex.lock();
        mUsePtp = usePtp;
        mMutex.unlock();
    }

    virtual bool threadLoop() {
        sMutex.lock();

        while (!mDone) {
        mMutex.lock();
        mFd = open("/dev/mtp_usb", O_RDWR);
            printf("open returned %d\n", mFd);
            if (mFd < 0) {
                LOGE("could not open MTP driver\n");
                sMutex.unlock();
                return false;
            }
        if (mFd >= 0) {
            ioctl(mFd, MTP_SET_INTERFACE_MODE,
                    (mUsePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP));

            mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775);
            mServer->addStorage(mStoragePath, mReserveSpace);

            sMutex.unlock();

            mMutex.unlock();
            mServer->run();
            sleep(1);

            sMutex.lock();
            mMutex.lock();

            close(mFd);
            mFd = -1;
            delete mServer;
            mServer = NULL;
        } else {
            LOGE("could not open MTP driver, errno: %d", errno);
        }

        JNIEnv* env = AndroidRuntime::getJNIEnv();
        env->SetIntField(mJavaServer, field_context, 0);
        env->DeleteGlobalRef(mJavaServer);
        sMutex.unlock();

        return false;
        mMutex.unlock();
        // delay a bit before retrying to avoid excessive spin
        if (!exitPending()) {
            sleep(1);
        }

    void stop() {
        sMutex.lock();
        mDone = true;
        sMutex.unlock();
        return true;
    }

    void sendObjectAdded(MtpObjectHandle handle) {
        sMutex.lock();
        mMutex.lock();
        if (mServer)
            mServer->sendObjectAdded(handle);
        sMutex.unlock();
        mMutex.unlock();
    }

    void sendObjectRemoved(MtpObjectHandle handle) {
        sMutex.lock();
        mMutex.lock();
        if (mServer)
            mServer->sendObjectRemoved(handle);
        sMutex.unlock();
        mMutex.unlock();
    }
};

// This smart pointer is necessary for preventing MtpThread from exiting too early
static sp<MtpThread> sThread;

#endif // HAVE_ANDROID_OS

static void
@@ -161,9 +136,8 @@ android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase,
    MtpDatabase* database = getMtpDatabase(env, javaDatabase);
    const char *storagePathStr = env->GetStringUTFChars(storagePath, NULL);

    MtpThread* thread = new MtpThread(database, storagePathStr,
            reserveSpace, env->NewGlobalRef(thiz));
    env->SetIntField(thiz, field_context, (int)thread);
    // create the thread and assign it to the smart pointer
    sThread = new MtpThread(database, storagePathStr, reserveSpace);

    env->ReleaseStringUTFChars(storagePath, storagePathStr);
#endif
@@ -173,7 +147,8 @@ static void
android_mtp_MtpServer_start(JNIEnv *env, jobject thiz)
{
#ifdef HAVE_ANDROID_OS
    MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
    MtpThread *thread = sThread.get();
    if (thread)
        thread->run("MtpThread");
#endif // HAVE_ANDROID_OS
}
@@ -182,9 +157,11 @@ static void
android_mtp_MtpServer_stop(JNIEnv *env, jobject thiz)
{
#ifdef HAVE_ANDROID_OS
    MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
    if (thread)
        thread->stop();
    MtpThread *thread = sThread.get();
    if (thread) {
        thread->requestExitAndWait();
        sThread = NULL;
    }
#endif
}

@@ -192,7 +169,7 @@ static void
android_mtp_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle)
{
#ifdef HAVE_ANDROID_OS
    MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
    MtpThread *thread = sThread.get();
    if (thread)
        thread->sendObjectAdded(handle);
#endif
@@ -202,7 +179,7 @@ static void
android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle)
{
#ifdef HAVE_ANDROID_OS
    MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
    MtpThread *thread = sThread.get();
    if (thread)
        thread->sendObjectRemoved(handle);
#endif
@@ -212,7 +189,7 @@ static void
android_mtp_MtpServer_set_ptp_mode(JNIEnv *env, jobject thiz, jboolean usePtp)
{
#ifdef HAVE_ANDROID_OS
    MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
    MtpThread *thread = sThread.get();
    if (thread)
        thread->setPtpMode(usePtp);
#endif
@@ -241,11 +218,6 @@ int register_android_mtp_MtpServer(JNIEnv *env)
        LOGE("Can't find android/mtp/MtpServer");
        return -1;
    }
    field_context = env->GetFieldID(clazz, "mNativeContext", "I");
    if (field_context == NULL) {
        LOGE("Can't find MtpServer.mNativeContext");
        return -1;
    }

    return AndroidRuntime::registerNativeMethods(env,
                "android/mtp/MtpServer", gMethods, NELEM(gMethods));