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

Commit dcc31946 authored by Mike Lockwood's avatar Mike Lockwood
Browse files

MTP: Clean up MtpServer initialization and threading:

Move thread from native to Java code
Remove the stop() method (the thread will exit on its own)

Change-Id: Ib897c3630162f82669a4ee8c187e8172da50b29d
parent 3fd13eb6
Loading
Loading
Loading
Loading
+10 −20
Original line number Diff line number Diff line
@@ -16,18 +16,13 @@

package android.mtp;

import android.util.Log;

/**
 * Java wrapper for MTP/PTP support as USB responder.
 * {@hide}
 */
public class MtpServer {

    private final Object mLock = new Object();
    private boolean mStarted;
public class MtpServer implements Runnable {

    private static final String TAG = "MtpServer";
    private int mNativeContext; // accessed by native methods

    static {
        System.loadLibrary("media_jni");
@@ -38,19 +33,14 @@ public class MtpServer {
    }

    public void start() {
        synchronized (mLock) {
            native_start();
            mStarted = true;
        }
        Thread thread = new Thread(this, "MtpServer");
        thread.start();
    }

    public void stop() {
        synchronized (mLock) {
            if (mStarted) {
                native_stop();
                mStarted = false;
            }
        }
    @Override
    public void run() {
        native_run();
        native_cleanup();
    }

    public void sendObjectAdded(int handle) {
@@ -70,8 +60,8 @@ public class MtpServer {
    }

    private native final void native_setup(MtpDatabase database, boolean usePtp);
    private native final void native_start();
    private native final void native_stop();
    private native final void native_run();
    private native final void native_cleanup();
    private native final void native_send_object_added(int handle);
    private native final void native_send_object_removed(int handle);
    private native final void native_add_storage(MtpStorage storage);
+65 −161
Original line number Diff line number Diff line
@@ -22,13 +22,8 @@
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <utils/threads.h>

#ifdef HAVE_ANDROID_OS
#include <linux/usb/f_mtp.h>
#endif

#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
@@ -39,8 +34,8 @@

using namespace android;

// MtpStorage class
jclass clazz_MtpStorage;
// MtpServer fields
static jfieldID field_MtpServer_nativeContext;

// MtpStorage fields
static jfieldID field_MtpStorage_storageId;
@@ -57,173 +52,78 @@ static Mutex sMutex;
// in android_mtp_MtpDatabase.cpp
extern MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database);

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

#ifdef HAVE_ANDROID_OS

static bool ExceptionCheck(void* env)
{
    return ((JNIEnv *)env)->ExceptionCheck();
static inline MtpServer* getMtpServer(JNIEnv *env, jobject thiz) {
    return (MtpServer*)env->GetIntField(thiz, field_MtpServer_nativeContext);
}

class MtpThread : public Thread {
private:
    MtpDatabase*    mDatabase;
    bool            mPtp;
    MtpServer*      mServer;
    MtpStorageList  mStorageList;
    int             mFd;

public:
    MtpThread(MtpDatabase* database, bool usePtp)
        :   mDatabase(database),
            mPtp(usePtp),
            mServer(NULL),
            mFd(-1)
static void
android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jboolean usePtp)
{
    }

    virtual ~MtpThread() {
    }

    void addStorage(MtpStorage *storage) {
        mStorageList.push(storage);
        if (mServer)
            mServer->addStorage(storage);
    }

    void removeStorage(MtpStorageID id) {
        MtpStorage* storage = mServer->getStorage(id);
        if (storage) {
            for (size_t i = 0; i < mStorageList.size(); i++) {
                if (mStorageList[i] == storage) {
                    mStorageList.removeAt(i);
                    break;
                }
            }
            if (mServer)
                mServer->removeStorage(storage);
            delete storage;
        }
    }

    void start() {
        run("MtpThread");
    }

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

        mFd = open("/dev/mtp_usb", O_RDWR);
        if (mFd >= 0) {
            mServer = new MtpServer(mFd, mDatabase, mPtp, AID_MEDIA_RW, 0664, 0775);
            for (size_t i = 0; i < mStorageList.size(); i++) {
                mServer->addStorage(mStorageList[i]);
            }
    int fd = open("/dev/mtp_usb", O_RDWR);
    if (fd >= 0) {
        MtpServer* server = new MtpServer(fd, getMtpDatabase(env, javaDatabase),
                usePtp, AID_MEDIA_RW, 0664, 0775);
        env->SetIntField(thiz, field_MtpServer_nativeContext, (int)server);
    } else {
        LOGE("could not open MTP driver, errno: %d", errno);
    }

        sMutex.unlock();
        mServer->run();
        sMutex.lock();

        close(mFd);
        mFd = -1;
        delete mServer;
        mServer = NULL;

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

        return true;
    }

    void sendObjectAdded(MtpObjectHandle handle) {
        if (mServer)
            mServer->sendObjectAdded(handle);
    }

    void sendObjectRemoved(MtpObjectHandle handle) {
        if (mServer)
            mServer->sendObjectRemoved(handle);
    }
};

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

#endif // HAVE_ANDROID_OS

static void
android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jboolean usePtp)
android_mtp_MtpServer_run(JNIEnv *env, jobject thiz)
{
#ifdef HAVE_ANDROID_OS
    // create the thread and assign it to the smart pointer
    sThread = new MtpThread(getMtpDatabase(env, javaDatabase), usePtp);
#endif
    MtpServer* server = getMtpServer(env, thiz);
    if (server)
        server->run();
    else
        LOGE("server is null in run");
}

static void
android_mtp_MtpServer_start(JNIEnv *env, jobject thiz)
android_mtp_MtpServer_cleanup(JNIEnv *env, jobject thiz)
{
#ifdef HAVE_ANDROID_OS
   sMutex.lock();
    MtpThread *thread = sThread.get();
    if (thread)
        thread->start();
    sMutex.unlock();
#endif // HAVE_ANDROID_OS
}
    Mutex::Autolock autoLock(sMutex);

static void
android_mtp_MtpServer_stop(JNIEnv *env, jobject thiz)
{
#ifdef HAVE_ANDROID_OS
    sMutex.lock();
    MtpThread *thread = sThread.get();
    if (thread) {
        thread->requestExitAndWait();
        sThread = NULL;
    MtpServer* server = getMtpServer(env, thiz);
    if (server) {
        delete server;
        env->SetIntField(thiz, field_MtpServer_nativeContext, 0);
    } else {
        LOGE("server is null in cleanup");
    }
    sMutex.unlock();
#endif
}

static void
android_mtp_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle)
{
#ifdef HAVE_ANDROID_OS
    sMutex.lock();
    MtpThread *thread = sThread.get();
    if (thread)
        thread->sendObjectAdded(handle);
    sMutex.unlock();
#endif
    Mutex::Autolock autoLock(sMutex);

    MtpServer* server = getMtpServer(env, thiz);
    if (server)
        server->sendObjectAdded(handle);
    else
        LOGE("server is null in send_object_added");
}

static void
android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle)
{
#ifdef HAVE_ANDROID_OS
    sMutex.lock();
    MtpThread *thread = sThread.get();
    if (thread)
        thread->sendObjectRemoved(handle);
    sMutex.unlock();
#endif
    Mutex::Autolock autoLock(sMutex);

    MtpServer* server = getMtpServer(env, thiz);
    if (server)
        server->sendObjectRemoved(handle);
    else
        LOGE("server is null in send_object_removed");
}

static void
android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
{
#ifdef HAVE_ANDROID_OS
    sMutex.lock();
    MtpThread *thread = sThread.get();
    if (thread) {
    Mutex::Autolock autoLock(sMutex);

    MtpServer* server = getMtpServer(env, thiz);
    if (server) {
        jint storageID = env->GetIntField(jstorage, field_MtpStorage_storageId);
        jstring path = (jstring)env->GetObjectField(jstorage, field_MtpStorage_path);
        jstring description = (jstring)env->GetObjectField(jstorage, field_MtpStorage_description);
@@ -237,7 +137,7 @@ android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
            if (descriptionStr != NULL) {
                MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr,
                        reserveSpace, removable, maxFileSize);
                thread->addStorage(storage);
                server->addStorage(storage);
                env->ReleaseStringUTFChars(path, pathStr);
                env->ReleaseStringUTFChars(description, descriptionStr);
            } else {
@@ -245,24 +145,24 @@ android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
            }
        }
    } else {
        LOGE("MtpThread is null in add_storage");
        LOGE("server is null in add_storage");
    }
    sMutex.unlock();
#endif
}

static void
android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId)
{
#ifdef HAVE_ANDROID_OS
    sMutex.lock();
    MtpThread *thread = sThread.get();
    if (thread)
        thread->removeStorage(storageId);
    else
        LOGE("MtpThread is null in remove_storage");
    sMutex.unlock();
#endif
    Mutex::Autolock autoLock(sMutex);

    MtpServer* server = getMtpServer(env, thiz);
    if (server) {
        MtpStorage* storage = server->getStorage(storageId);
        if (storage) {
            server->removeStorage(storage);
            delete storage;
        }
    } else
        LOGE("server is null in remove_storage");
}

// ----------------------------------------------------------------------------
@@ -270,8 +170,8 @@ android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId)
static JNINativeMethod gMethods[] = {
    {"native_setup",                "(Landroid/mtp/MtpDatabase;Z)V",
                                            (void *)android_mtp_MtpServer_setup},
    {"native_start",                "()V",  (void *)android_mtp_MtpServer_start},
    {"native_stop",                 "()V",  (void *)android_mtp_MtpServer_stop},
    {"native_run",                  "()V",  (void *)android_mtp_MtpServer_run},
    {"native_cleanup",              "()V",  (void *)android_mtp_MtpServer_cleanup},
    {"native_send_object_added",    "(I)V", (void *)android_mtp_MtpServer_send_object_added},
    {"native_send_object_removed",  "(I)V", (void *)android_mtp_MtpServer_send_object_removed},
    {"native_add_storage",          "(Landroid/mtp/MtpStorage;)V",
@@ -320,13 +220,17 @@ int register_android_mtp_MtpServer(JNIEnv *env)
        LOGE("Can't find MtpStorage.mMaxFileSize");
        return -1;
    }
    clazz_MtpStorage = (jclass)env->NewGlobalRef(clazz);

    clazz = env->FindClass("android/mtp/MtpServer");
    if (clazz == NULL) {
        LOGE("Can't find android/mtp/MtpServer");
        return -1;
    }
    field_MtpServer_nativeContext = env->GetFieldID(clazz, "mNativeContext", "I");
    if (field_MtpServer_nativeContext == NULL) {
        LOGE("Can't find MtpServer.mNativeContext");
        return -1;
    }

    return AndroidRuntime::registerNativeMethods(env,
                "android/mtp/MtpServer", gMethods, NELEM(gMethods));
+2 −0
Original line number Diff line number Diff line
@@ -237,6 +237,8 @@ void MtpServer::run() {

    if (mSessionOpen)
        mDatabase->sessionEnded();
    close(fd);
    mFD = -1;
}

void MtpServer::sendObjectAdded(MtpObjectHandle handle) {