1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/logging.h" 6 #include "base/mac/bundle_locations.h" 7 #include "base/mac/mac_util.h" 8 #include "base/strings/string_util.h" 9 #include "base/strings/sys_string_conversions.h" 10 #include "base/time/time.h" 11 #import "chrome/browser/ui/cocoa/about_ipc_controller.h" 12 #include "content/public/browser/browser_ipc_logging.h" 13 14 #if defined(IPC_MESSAGE_LOG_ENABLED) 15 16 @implementation CocoaLogData 17 18 - (id)initWithLogData:(const IPC::LogData&)data { 19 if ((self = [super init])) { 20 data_ = data; 21 // data_.message_name may not have been filled in if it originated 22 // somewhere other than the browser process. 23 if (data_.message_name == "") 24 IPC::Logging::GetMessageText(data_.type, &data_.message_name, NULL, NULL); 25 } 26 return self; 27 } 28 29 - (NSString*)time { 30 base::Time t = base::Time::FromInternalValue(data_.sent); 31 base::Time::Exploded exploded; 32 t.LocalExplode(&exploded); 33 return [NSString stringWithFormat:@"%02d:%02d:%02d.%03d", 34 exploded.hour, exploded.minute, 35 exploded.second, exploded.millisecond]; 36 } 37 38 - (NSString*)channel { 39 return base::SysUTF8ToNSString(data_.channel); 40 } 41 42 - (NSString*)message { 43 if (data_.message_name == "") { 44 int high = data_.type >> 12; 45 int low = data_.type - (high<<12); 46 return [NSString stringWithFormat:@"type=(%d,%d) 0x%x,0x%x", 47 high, low, high, low]; 48 } 49 else { 50 return base::SysUTF8ToNSString(data_.message_name); 51 } 52 } 53 54 - (NSString*)flags { 55 return base::SysUTF8ToNSString(data_.flags); 56 } 57 58 - (NSString*)dispatch { 59 base::Time sent = base::Time::FromInternalValue(data_.sent); 60 int64 delta = (base::Time::FromInternalValue(data_.receive) - 61 sent).InMilliseconds(); 62 return [NSString stringWithFormat:@"%d", delta ? (int)delta : 0]; 63 } 64 65 - (NSString*)process { 66 base::TimeDelta delta = (base::Time::FromInternalValue(data_.dispatch) - 67 base::Time::FromInternalValue(data_.receive)); 68 int64 t = delta.InMilliseconds(); 69 return [NSString stringWithFormat:@"%d", t ? (int)t : 0]; 70 } 71 72 - (NSString*)parameters { 73 return base::SysUTF8ToNSString(data_.params); 74 } 75 76 @end 77 78 namespace { 79 AboutIPCController* gSharedController = nil; 80 } 81 82 @implementation AboutIPCController 83 84 + (AboutIPCController*)sharedController { 85 if (gSharedController == nil) 86 gSharedController = [[AboutIPCController alloc] init]; 87 return gSharedController; 88 } 89 90 - (id)init { 91 NSString* nibpath = [base::mac::FrameworkBundle() pathForResource:@"AboutIPC" 92 ofType:@"nib"]; 93 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { 94 // Default to all on 95 appCache_ = view_ = utilityHost_ = viewHost_ = plugin_ = 96 npObject_ = devTools_ = pluginProcessing_ = userString1_ = 97 userString2_ = userString3_ = YES; 98 } 99 return self; 100 } 101 102 - (void)dealloc { 103 if (gSharedController == self) 104 gSharedController = nil; 105 content::EnableIPCLogging(false); // just in case... 106 IPC::Logging::GetInstance()->SetConsumer(NULL); 107 [super dealloc]; 108 } 109 110 - (void)awakeFromNib { 111 // Running Chrome with the --ipc-logging switch might cause it to 112 // be enabled before the about:ipc window comes up; accomodate. 113 [self updateVisibleRunState]; 114 115 // We are now able to display information, so let'er rip. 116 bridge_.reset(new AboutIPCBridge(self)); 117 IPC::Logging::GetInstance()->SetConsumer(bridge_.get()); 118 } 119 120 // Delegate callback. Closing the window means there is no more need 121 // for the me, the controller. 122 - (void)windowWillClose:(NSNotification*)notification { 123 [self autorelease]; 124 } 125 126 - (void)updateVisibleRunState { 127 if (IPC::Logging::GetInstance()->Enabled()) 128 [startStopButton_ setTitle:@"Stop"]; 129 else 130 [startStopButton_ setTitle:@"Start"]; 131 } 132 133 - (IBAction)startStop:(id)sender { 134 content::EnableIPCLogging(!IPC::Logging::GetInstance()->Enabled()); 135 [self updateVisibleRunState]; 136 } 137 138 - (IBAction)clear:(id)sender { 139 [dataController_ setContent:[NSMutableArray array]]; 140 [eventCount_ setStringValue:@"0"]; 141 [filteredEventCount_ setStringValue:@"0"]; 142 filteredEventCounter_ = 0; 143 } 144 145 // Return YES if we should filter this out; else NO. 146 // Just to be clear, [@"any string" hasPrefix:@""] returns NO. 147 - (BOOL)filterOut:(CocoaLogData*)data { 148 NSString* name = [data message]; 149 if ((appCache_) && [name hasPrefix:@"AppCache"]) 150 return NO; 151 if ((view_) && [name hasPrefix:@"ViewMsg"]) 152 return NO; 153 if ((utilityHost_) && [name hasPrefix:@"UtilityHost"]) 154 return NO; 155 if ((viewHost_) && [name hasPrefix:@"ViewHost"]) 156 return NO; 157 if ((plugin_) && [name hasPrefix:@"PluginMsg"]) 158 return NO; 159 if ((npObject_) && [name hasPrefix:@"NPObject"]) 160 return NO; 161 if ((devTools_) && [name hasPrefix:@"DevTools"]) 162 return NO; 163 if ((pluginProcessing_) && [name hasPrefix:@"PluginProcessing"]) 164 return NO; 165 if ((userString1_) && ([name hasPrefix:[userStringTextField1_ stringValue]])) 166 return NO; 167 if ((userString2_) && ([name hasPrefix:[userStringTextField2_ stringValue]])) 168 return NO; 169 if ((userString3_) && ([name hasPrefix:[userStringTextField3_ stringValue]])) 170 return NO; 171 172 // Special case the unknown type. 173 if ([name hasPrefix:@"type="]) 174 return NO; 175 176 return YES; // filter out. 177 } 178 179 - (void)log:(CocoaLogData*)data { 180 if ([self filterOut:data]) { 181 [filteredEventCount_ setStringValue:[NSString stringWithFormat:@"%d", 182 ++filteredEventCounter_]]; 183 return; 184 } 185 [dataController_ addObject:data]; 186 NSUInteger count = [[dataController_ arrangedObjects] count]; 187 // Uncomment if you want scroll-to-end behavior... but seems expensive. 188 // [tableView_ scrollRowToVisible:count-1]; 189 [eventCount_ setStringValue:[NSString stringWithFormat:@"%ld", 190 static_cast<long>(count)]]; 191 } 192 193 - (void)setDisplayViewMessages:(BOOL)display { 194 view_ = display; 195 } 196 197 @end 198 199 #endif // IPC_MESSAGE_LOG_ENABLED 200 201