Merge "MTP: Remove an unnecessary thread from the MtpClient class."
diff --git a/media/java/android/media/MtpClient.java b/media/java/android/media/MtpClient.java
index ad6640f..0fe9bb4 100644
--- a/media/java/android/media/MtpClient.java
+++ b/media/java/android/media/MtpClient.java
@@ -44,9 +44,12 @@
native_finalize();
}
- public void start() {
- mEventThread = new MtpEventThread();
- mEventThread.start();
+ public boolean start() {
+ return native_start();
+ }
+
+ public void stop() {
+ native_stop();
}
public boolean deleteObject(int deviceID, int objectID) {
@@ -61,24 +64,6 @@
return native_get_storage_id(deviceID, objectID);
}
- private class MtpEventThread extends Thread {
-
- private boolean mDone;
-
- public MtpEventThread() {
- super("MtpEventThread");
- }
-
- public void run() {
- Log.d(TAG, "MtpEventThread starting");
- while (!mDone) {
- // this will wait for an event from an MTP device
- native_wait_for_event();
- }
- Log.d(TAG, "MtpEventThread exiting");
- }
- }
-
public interface Listener {
// called when a new MTP device has been discovered
void deviceAdded(int id);
@@ -99,14 +84,13 @@
mListener.deviceRemoved(id);
}
- private MtpEventThread mEventThread;
-
// used by the JNI code
private int mNativeContext;
private native final void native_setup();
private native final void native_finalize();
- private native void native_wait_for_event();
+ private native boolean native_start();
+ private native void native_stop();
private native boolean native_delete_object(int deviceID, int objectID);
private native int native_get_parent(int deviceID, int objectID);
private native int native_get_storage_id(int deviceID, int objectID);
diff --git a/media/jni/android_media_MtpClient.cpp b/media/jni/android_media_MtpClient.cpp
index 2328889..5c397a6 100644
--- a/media/jni/android_media_MtpClient.cpp
+++ b/media/jni/android_media_MtpClient.cpp
@@ -22,7 +22,6 @@
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
-#include <utils/threads.h>
#include "jni.h"
#include "JNIHelp.h"
@@ -39,34 +38,25 @@
static jmethodID method_deviceRemoved;
static jfieldID field_context;
+static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ LOGE("An exception was thrown by callback '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+}
+
class MyClient : public MtpClient {
private:
-
- enum {
- kDeviceAdded = 1,
- kDeviceRemoved,
- };
-
virtual void deviceAdded(MtpDevice *device);
virtual void deviceRemoved(MtpDevice *device);
- bool reportDeviceAdded(JNIEnv *env, MtpDevice *device);
- bool reportDeviceRemoved(JNIEnv *env, MtpDevice *device);
-
- JNIEnv* mEnv;
jobject mClient;
- Mutex mEventLock;
- Condition mEventCondition;
- Mutex mAckLock;
- Condition mAckCondition;
- int mEvent;
MtpDevice* mEventDevice;
public:
MyClient(JNIEnv *env, jobject client);
- virtual ~MyClient();
- void waitForEvent(JNIEnv *env);
-
+ void cleanup(JNIEnv *env);
};
MtpClient* get_client_from_object(JNIEnv* env, jobject javaClient)
@@ -76,87 +66,36 @@
MyClient::MyClient(JNIEnv *env, jobject client)
- : mEnv(env),
- mClient(env->NewGlobalRef(client)),
- mEvent(0),
- mEventDevice(NULL)
+ : mClient(env->NewGlobalRef(client))
{
}
-MyClient::~MyClient() {
- mEnv->DeleteGlobalRef(mClient);
+void MyClient::cleanup(JNIEnv *env) {
+ env->DeleteGlobalRef(mClient);
}
-
void MyClient::deviceAdded(MtpDevice *device) {
- LOGD("MyClient::deviceAdded\n");
- mAckLock.lock();
- mEventLock.lock();
- mEvent = kDeviceAdded;
- mEventDevice = device;
- mEventCondition.signal();
- mEventLock.unlock();
- mAckCondition.wait(mAckLock);
- mAckLock.unlock();
-}
-
-void MyClient::deviceRemoved(MtpDevice *device) {
- LOGD("MyClient::deviceRemoved\n");
- mAckLock.lock();
- mEventLock.lock();
- mEvent = kDeviceRemoved;
- mEventDevice = device;
- mEventCondition.signal();
- mEventLock.unlock();
- mAckCondition.wait(mAckLock);
- mAckLock.unlock();
-}
-
-bool MyClient::reportDeviceAdded(JNIEnv *env, MtpDevice *device) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
const char* name = device->getDeviceName();
- LOGD("MyClient::reportDeviceAdded %s\n", name);
+ LOGD("MyClient::deviceAdded %s\n", name);
env->CallVoidMethod(mClient, method_deviceAdded, device->getID());
- return (!env->ExceptionCheck());
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
-bool MyClient::reportDeviceRemoved(JNIEnv *env, MtpDevice *device) {
- const char* name = device->getDeviceName();
- LOGD("MyClient::reportDeviceRemoved %s\n", name);
+void MyClient::deviceRemoved(MtpDevice *device) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ const char* name = device->getDeviceName();
+ LOGD("MyClient::deviceRemoved %s\n", name);
env->CallVoidMethod(mClient, method_deviceRemoved, device->getID());
- return (!env->ExceptionCheck());
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
-void MyClient::waitForEvent(JNIEnv *env) {
- mEventLock.lock();
- mEventCondition.wait(mEventLock);
- mEventLock.unlock();
-
- switch (mEvent) {
- case kDeviceAdded:
- reportDeviceAdded(env, mEventDevice);
- break;
- case kDeviceRemoved:
- reportDeviceRemoved(env, mEventDevice);
- break;
- }
-
- mAckLock.lock();
- mAckCondition.signal();
- mAckLock.unlock();
-}
-
-
// ----------------------------------------------------------------------------
-static bool ExceptionCheck(void* env)
-{
- return ((JNIEnv *)env)->ExceptionCheck();
-}
-
static void
android_media_MtpClient_setup(JNIEnv *env, jobject thiz)
{
@@ -171,15 +110,25 @@
{
LOGD("finalize\n");
MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
+ client->cleanup(env);
delete client;
+ env->SetIntField(thiz, field_context, 0);
+}
+
+static jboolean
+android_media_MtpClient_start(JNIEnv *env, jobject thiz)
+{
+ LOGD("start\n");
+ MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
+ return client->start();
}
static void
-android_media_MtpClient_wait_for_event(JNIEnv *env, jobject thiz)
+android_media_MtpClient_stop(JNIEnv *env, jobject thiz)
{
- LOGD("wait_for_event\n");
+ LOGD("stop\n");
MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
- client->waitForEvent(env);
+ client->stop();
}
static jboolean
@@ -223,7 +172,8 @@
static JNINativeMethod gMethods[] = {
{"native_setup", "()V", (void *)android_media_MtpClient_setup},
{"native_finalize", "()V", (void *)android_media_MtpClient_finalize},
- {"native_wait_for_event", "()V", (void *)android_media_MtpClient_wait_for_event},
+ {"native_start", "()Z", (void *)android_media_MtpClient_start},
+ {"native_stop", "()V", (void *)android_media_MtpClient_stop},
{"native_delete_object", "(II)Z", (void *)android_media_MtpClient_delete_object},
{"native_get_parent", "(II)I", (void *)android_media_MtpClient_get_parent},
{"native_get_storage_id", "(II)I", (void *)android_media_MtpClient_get_storage_id},
diff --git a/media/mtp/MtpClient.cpp b/media/mtp/MtpClient.cpp
index fbf1c77..b4c47af8 100644
--- a/media/mtp/MtpClient.cpp
+++ b/media/mtp/MtpClient.cpp
@@ -27,6 +27,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
+#include <utils/threads.h>
#include <usbhost/usbhost.h>
#include <linux/version.h>
@@ -38,34 +39,59 @@
namespace android {
+class MtpClientThread : public Thread {
+private:
+ MtpClient* mClient;
+
+public:
+ MtpClientThread(MtpClient* client)
+ : mClient(client)
+ {
+ }
+
+ virtual bool threadLoop() {
+ return mClient->threadLoop();
+ }
+};
+
+
MtpClient::MtpClient()
- : mStarted(false)
+ : mThread(NULL),
+ mUsbHostContext(NULL),
+ mDone(false)
{
}
MtpClient::~MtpClient() {
+ usb_host_cleanup(mUsbHostContext);
}
bool MtpClient::start() {
- if (mStarted)
+ if (mThread)
return true;
- if (usb_host_init(usb_device_added, usb_device_removed, this)) {
- LOGE("MtpClient::start failed\n");
+ mUsbHostContext = usb_host_init();
+ if (!mUsbHostContext)
return false;
- }
- mStarted = true;
+
+ mThread = new MtpClientThread(this);
+ mThread->run("MtpClientThread");
+
return true;
}
-void MtpClient::usbDeviceAdded(const char *devname) {
+void MtpClient::stop() {
+ mDone = true;
+}
+
+bool MtpClient::usbDeviceAdded(const char *devname) {
struct usb_descriptor_header* desc;
struct usb_descriptor_iter iter;
struct usb_device *device = usb_device_open(devname);
if (!device) {
LOGE("usb_device_open failed\n");
- return;
+ return mDone;
}
usb_descriptor_iter_init(device, &iter);
@@ -90,7 +116,7 @@
ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
LOGE("endpoints not found\n");
- return;
+ return mDone;
}
if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
@@ -104,7 +130,7 @@
}
if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
LOGE("endpoints not found\n");
- return;
+ return mDone;
}
struct usb_endpoint *ep_in = usb_endpoint_open(device, ep_in_desc);
@@ -116,7 +142,7 @@
usb_endpoint_close(ep_in);
usb_endpoint_close(ep_out);
usb_endpoint_close(ep_intr);
- return;
+ return mDone;
}
MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
@@ -124,12 +150,13 @@
mDeviceList.add(mtpDevice);
mtpDevice->initialize();
deviceAdded(mtpDevice);
- return;
+ return mDone;
}
}
}
usb_device_close(device);
+ return mDone;
}
MtpDevice* MtpClient::getDevice(int id) {
@@ -141,7 +168,7 @@
return NULL;
}
-void MtpClient::usbDeviceRemoved(const char *devname) {
+bool MtpClient::usbDeviceRemoved(const char *devname) {
for (int i = 0; i < mDeviceList.size(); i++) {
MtpDevice* device = mDeviceList[i];
if (!strcmp(devname, device->getDeviceName())) {
@@ -152,16 +179,22 @@
break;
}
}
+ return mDone;
}
-void MtpClient::usb_device_added(const char *devname, void* client_data) {
+bool MtpClient::threadLoop() {
+ usb_host_run(mUsbHostContext, usb_device_added, usb_device_removed, this);
+ return false;
+}
+
+int MtpClient::usb_device_added(const char *devname, void* client_data) {
LOGD("usb_device_added %s\n", devname);
- ((MtpClient *)client_data)->usbDeviceAdded(devname);
+ return ((MtpClient *)client_data)->usbDeviceAdded(devname);
}
-void MtpClient::usb_device_removed(const char *devname, void* client_data) {
+int MtpClient::usb_device_removed(const char *devname, void* client_data) {
LOGD("usb_device_removed %s\n", devname);
- ((MtpClient *)client_data)->usbDeviceRemoved(devname);
+ return ((MtpClient *)client_data)->usbDeviceRemoved(devname);
}
} // namespace android
diff --git a/media/mtp/MtpClient.h b/media/mtp/MtpClient.h
index d87c226..907a80b 100644
--- a/media/mtp/MtpClient.h
+++ b/media/mtp/MtpClient.h
@@ -19,18 +19,25 @@
#include "MtpTypes.h"
+struct usb_host_context;
+
namespace android {
+class MtpClientThread;
+
class MtpClient {
private:
- MtpDeviceList mDeviceList;
- bool mStarted;
+ MtpDeviceList mDeviceList;
+ MtpClientThread* mThread;
+ struct usb_host_context* mUsbHostContext;
+ bool mDone;
public:
MtpClient();
virtual ~MtpClient();
bool start();
+ void stop();
inline MtpDeviceList& getDeviceList() { return mDeviceList; }
MtpDevice* getDevice(int id);
@@ -40,10 +47,14 @@
virtual void deviceRemoved(MtpDevice *device) = 0;
private:
- void usbDeviceAdded(const char *devname);
- void usbDeviceRemoved(const char *devname);
- static void usb_device_added(const char *devname, void* client_data);
- static void usb_device_removed(const char *devname, void* client_data);
+ // these return true if we should stop monitoring USB and clean up
+ bool usbDeviceAdded(const char *devname);
+ bool usbDeviceRemoved(const char *devname);
+
+ friend class MtpClientThread;
+ bool threadLoop();
+ static int usb_device_added(const char *devname, void* client_data);
+ static int usb_device_removed(const char *devname, void* client_data);
};
}; // namespace android