Index: base/system_monitor/system_monitor_mac.mm |
diff --git a/base/system_monitor/system_monitor_mac.mm b/base/system_monitor/system_monitor_mac.mm |
index baaadf052db913eb7f3c548f81c545901f6192e8..f9a92cc911208b11cceff20040633e92636d7e60 100644 |
--- a/base/system_monitor/system_monitor_mac.mm |
+++ b/base/system_monitor/system_monitor_mac.mm |
@@ -7,9 +7,14 @@ |
#include "base/system_monitor/system_monitor.h" |
+#include <Carbon/Carbon.h> |
+#include <CoreFoundation/CoreFoundation.h> |
#include <IOKit/pwr_mgt/IOPMLib.h> |
#include <IOKit/IOMessage.h> |
+#include "base/mac/foundation_util.h" |
+#include "base/sys_string_conversions.h" |
+ |
namespace base { |
namespace { |
@@ -37,6 +42,73 @@ void SystemPowerEventCallback(void*, |
} |
} |
+bool GetDeviceInfo(unsigned long device_number, std::string* name, |
+ FilePath* location) { |
+ ICACopyObjectPropertyDictionaryPB properties_request; |
+ properties_request.object = device_number; |
+ CFDictionaryRef device_properties; |
+ properties_request.theDict = &device_properties; |
+ OSErr ret = ICACopyObjectPropertyDictionary(&properties_request, NULL); |
+ CHECK_EQ(ret, noErr); |
+ |
+ // For now, we only support mass storage media devices. |
+ CFStringRef volume = mac::GetValueFromDictionary<CFStringRef>( |
+ device_properties, CFSTR("volume")); |
+ if (volume == NULL) { |
+ CFRelease(device_properties); |
+ return false; |
+ } |
+ *location = FilePath("/Volumes/").Append(SysCFStringRefToUTF8(volume)); |
+ |
+ CFStringRef device_name = mac::GetValueFromDictionary<CFStringRef>( |
+ device_properties, CFSTR("ICAUserAssignedDeviceNameKey")); |
+ if (device_name == NULL) { |
+ device_name = mac::GetValueFromDictionary<CFStringRef>( |
+ device_properties, CFSTR("ifil")); |
+ } |
+ if (device_name == NULL) { |
+ CFRelease(device_properties); |
+ return false; |
+ } |
+ *name = SysCFStringRefToUTF8(device_name); |
+ |
+ CFRelease(device_properties); |
+ return true; |
+} |
+ |
+void MediaDeviceNotificationCallback(CFStringRef notification_type, |
+ CFDictionaryRef notification_dictionary) { |
+ bool attach = false; |
+ if (CFStringCompare(notification_type, kICANotificationTypeDeviceAdded, 0) == |
+ kCFCompareEqualTo) { |
+ attach = true; |
+ } else if (CFStringCompare(notification_type, |
+ kICANotificationTypeDeviceRemoved, 0) != |
+ kCFCompareEqualTo) { |
+ return; |
+ } |
+ CFNumberRef refcon_object = mac::GetValueFromDictionary<CFNumberRef>( |
+ notification_dictionary, kICARefconKey); |
+ unsigned long refcon; |
+ CFNumberGetValue(refcon_object, kCFNumberLongType, &refcon); |
+ SystemMonitor* system_monitor = reinterpret_cast<SystemMonitor*>(refcon); |
+ |
+ CFNumberRef device_number_object = mac::GetValueFromDictionary<CFNumberRef>( |
+ notification_dictionary, kICANotificationDeviceICAObjectKey); |
+ unsigned long device_number; |
+ CFNumberGetValue(device_number_object, kCFNumberIntType, &device_number); |
+ if (attach) { |
+ std::string device_name; |
+ FilePath location; |
+ if (GetDeviceInfo(device_number, &device_name, &location)) { |
+ system_monitor->ProcessMediaDeviceAttached(device_number, device_name, |
+ location); |
+ } |
+ } else { |
+ system_monitor->ProcessMediaDeviceDetached(device_number); |
+ } |
+} |
+ |
} // namespace |
// The reason we can't include this code in the constructor is because |
@@ -69,6 +141,20 @@ void SystemMonitor::PlatformInit() { |
CFRunLoopGetCurrent(), |
IONotificationPortGetRunLoopSource(g_notification_port_ref), |
kCFRunLoopCommonModes); |
+ |
+ ICARegisterForEventNotificationPB notification_request; |
+ notification_request.header.refcon = reinterpret_cast<unsigned long>(this); |
+ notification_request.objectOfInterest = 0; // Zero means all objects |
+ CFStringRef events_of_interest_array[] = {kICANotificationTypeDeviceAdded, |
+ kICANotificationTypeDeviceRemoved}; |
+ CFArrayRef events_of_interest = |
+ CFArrayCreate(NULL, (const void**)&events_of_interest_array, 2, |
+ &kCFTypeArrayCallBacks); |
+ notification_request.eventsOfInterest = events_of_interest; |
+ notification_request.notificationProc = &MediaDeviceNotificationCallback; |
+ notification_request.options = NULL; |
+ OSErr err = ICARegisterForEventNotification(¬ification_request, NULL); |
+ CHECK_EQ(err, noErr); |
} |
void SystemMonitor::PlatformDestroy() { |