Fail gracefully when libusb_init fails

BUG=280668

Review URL: https://chromiumcodereview.appspot.com/23571007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221508 0039d316-1c4b-4281-b951-d872f2087c98
parent d34e4070
...@@ -59,6 +59,8 @@ namespace { ...@@ -59,6 +59,8 @@ namespace {
const char kDataKey[] = "data"; const char kDataKey[] = "data";
const char kResultCodeKey[] = "resultCode"; const char kResultCodeKey[] = "resultCode";
const char kErrorInitService[] = "Failed to initialize USB service.";
const char kErrorOpen[] = "Failed to open device."; const char kErrorOpen[] = "Failed to open device.";
const char kErrorCancelled[] = "Transfer was cancelled."; const char kErrorCancelled[] = "Transfer was cancelled.";
const char kErrorDisconnect[] = "Device disconnected."; const char kErrorDisconnect[] = "Device disconnected.";
...@@ -412,6 +414,10 @@ UsbAsyncApiFunction::GetDeviceOrOrCompleteWithError( ...@@ -412,6 +414,10 @@ UsbAsyncApiFunction::GetDeviceOrOrCompleteWithError(
} }
UsbService* service = UsbService::GetInstance(); UsbService* service = UsbService::GetInstance();
if (!service) {
CompleteWithError(kErrorInitService);
return NULL;
}
scoped_refptr<UsbDevice> device; scoped_refptr<UsbDevice> device;
device = service->GetDeviceById(input_device.device); device = service->GetDeviceById(input_device.device);
...@@ -537,6 +543,11 @@ void UsbFindDevicesFunction::AsyncWorkStart() { ...@@ -537,6 +543,11 @@ void UsbFindDevicesFunction::AsyncWorkStart() {
} }
UsbService *service = UsbService::GetInstance(); UsbService *service = UsbService::GetInstance();
if (!service) {
CompleteWithError(kErrorInitService);
return;
}
ScopedDeviceVector devices(new DeviceVector()); ScopedDeviceVector devices(new DeviceVector());
service->GetDevices(devices.get()); service->GetDevices(devices.get());
...@@ -624,6 +635,11 @@ void UsbGetDevicesFunction::AsyncWorkStart() { ...@@ -624,6 +635,11 @@ void UsbGetDevicesFunction::AsyncWorkStart() {
} }
UsbService* service = UsbService::GetInstance(); UsbService* service = UsbService::GetInstance();
if (!service) {
CompleteWithError(kErrorInitService);
return;
}
DeviceVector devices; DeviceVector devices;
service->GetDevices(&devices); service->GetDevices(&devices);
......
...@@ -60,9 +60,8 @@ void UsbContext::UsbEventHandler::ThreadMain() { ...@@ -60,9 +60,8 @@ void UsbContext::UsbEventHandler::ThreadMain() {
VLOG(1) << "UsbEventHandler shutting down."; VLOG(1) << "UsbEventHandler shutting down.";
} }
UsbContext::UsbContext() : context_(NULL) { UsbContext::UsbContext(PlatformUsbContext context) : context_(context) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
CHECK_EQ(0, libusb_init(&context_)) << "Cannot initialize libusb";
event_handler_ = new UsbEventHandler(context_); event_handler_ = new UsbEventHandler(context_);
} }
......
...@@ -27,7 +27,7 @@ class UsbContext : public base::RefCountedThreadSafe<UsbContext> { ...@@ -27,7 +27,7 @@ class UsbContext : public base::RefCountedThreadSafe<UsbContext> {
friend class UsbService; friend class UsbService;
friend class base::RefCountedThreadSafe<UsbContext>; friend class base::RefCountedThreadSafe<UsbContext>;
UsbContext(); explicit UsbContext(PlatformUsbContext context);
virtual ~UsbContext(); virtual ~UsbContext();
private: private:
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/threading/platform_thread.h" #include "base/threading/platform_thread.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libusb/src/libusb/libusb.h"
namespace { namespace {
...@@ -14,7 +15,8 @@ class UsbContextTest : public testing::Test { ...@@ -14,7 +15,8 @@ class UsbContextTest : public testing::Test {
protected: protected:
class UsbContextForTest : public UsbContext { class UsbContextForTest : public UsbContext {
public: public:
UsbContextForTest() : UsbContext() {} explicit UsbContextForTest(PlatformUsbContext context)
: UsbContext(context) {}
private: private:
virtual ~UsbContextForTest() {} virtual ~UsbContextForTest() {}
DISALLOW_COPY_AND_ASSIGN(UsbContextForTest); DISALLOW_COPY_AND_ASSIGN(UsbContextForTest);
...@@ -36,7 +38,10 @@ class UsbContextTest : public testing::Test { ...@@ -36,7 +38,10 @@ class UsbContextTest : public testing::Test {
TEST_F(UsbContextTest, MAYBE_GracefulShutdown) { TEST_F(UsbContextTest, MAYBE_GracefulShutdown) {
base::TimeTicks start = base::TimeTicks::Now(); base::TimeTicks start = base::TimeTicks::Now();
{ {
scoped_refptr<UsbContextForTest> context(new UsbContextForTest()); PlatformUsbContext platform_context;
ASSERT_EQ(LIBUSB_SUCCESS, libusb_init(&platform_context));
scoped_refptr<UsbContextForTest> context(
new UsbContextForTest(platform_context));
} }
base::TimeDelta elapse = base::TimeTicks::Now() - start; base::TimeDelta elapse = base::TimeTicks::Now() - start;
if (elapse > base::TimeDelta::FromSeconds(2)) { if (elapse > base::TimeDelta::FromSeconds(2)) {
......
...@@ -64,8 +64,8 @@ class ExitObserver : public content::NotificationObserver { ...@@ -64,8 +64,8 @@ class ExitObserver : public content::NotificationObserver {
using content::BrowserThread; using content::BrowserThread;
UsbService::UsbService() UsbService::UsbService(PlatformUsbContext context)
: context_(new UsbContext()), : context_(new UsbContext(context)),
next_unique_id_(0) { next_unique_id_(0) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
// Will be deleted upon NOTIFICATION_APP_TERMINATING. // Will be deleted upon NOTIFICATION_APP_TERMINATING.
...@@ -79,10 +79,22 @@ UsbService::~UsbService() { ...@@ -79,10 +79,22 @@ UsbService::~UsbService() {
} }
} }
struct InitUsbContextTraits : public LeakySingletonTraits<UsbService> {
// LeakySingletonTraits<UsbService>
static UsbService* New() {
PlatformUsbContext context = NULL;
if (libusb_init(&context) != LIBUSB_SUCCESS)
return NULL;
if (!context)
return NULL;
return new UsbService(context);
}
};
UsbService* UsbService::GetInstance() { UsbService* UsbService::GetInstance() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
// UsbService deletes itself upon APP_TERMINATING. // UsbService deletes itself upon APP_TERMINATING.
return Singleton<UsbService, LeakySingletonTraits<UsbService> >::get(); return Singleton<UsbService, InitUsbContextTraits>::get();
} }
void UsbService::GetDevices(std::vector<scoped_refptr<UsbDevice> >* devices) { void UsbService::GetDevices(std::vector<scoped_refptr<UsbDevice> >* devices) {
......
...@@ -20,9 +20,11 @@ template <class T> class DeleteHelper; ...@@ -20,9 +20,11 @@ template <class T> class DeleteHelper;
} // namespace base } // namespace base
struct InitUsbContextTraits;
template <typename T> struct DefaultSingletonTraits; template <typename T> struct DefaultSingletonTraits;
typedef struct libusb_device* PlatformUsbDevice; typedef struct libusb_device* PlatformUsbDevice;
typedef struct libusb_context* PlatformUsbContext;
class UsbContext; class UsbContext;
class UsbDevice; class UsbDevice;
...@@ -37,6 +39,7 @@ class UsbService { ...@@ -37,6 +39,7 @@ class UsbService {
ScopedDeviceVector; ScopedDeviceVector;
// Must be called on FILE thread. // Must be called on FILE thread.
// Returns NULL when failed to initialized.
static UsbService* GetInstance(); static UsbService* GetInstance();
scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id); scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id);
...@@ -47,10 +50,11 @@ class UsbService { ...@@ -47,10 +50,11 @@ class UsbService {
void GetDevices(std::vector<scoped_refptr<UsbDevice> >* devices); void GetDevices(std::vector<scoped_refptr<UsbDevice> >* devices);
private: private:
friend struct InitUsbContextTraits;
friend struct DefaultSingletonTraits<UsbService>; friend struct DefaultSingletonTraits<UsbService>;
friend class base::DeleteHelper<UsbService>; friend class base::DeleteHelper<UsbService>;
UsbService(); explicit UsbService(PlatformUsbContext context);
virtual ~UsbService(); virtual ~UsbService();
// Return true if |device|'s vendor and product identifiers match |vendor_id| // Return true if |device|'s vendor and product identifiers match |vendor_id|
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment