1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.ddms.systrace; 18 19 import org.eclipse.jface.dialogs.TitleAreaDialog; 20 import org.eclipse.swt.SWT; 21 import org.eclipse.swt.events.ModifyEvent; 22 import org.eclipse.swt.events.ModifyListener; 23 import org.eclipse.swt.events.SelectionAdapter; 24 import org.eclipse.swt.events.SelectionEvent; 25 import org.eclipse.swt.layout.GridData; 26 import org.eclipse.swt.layout.GridLayout; 27 import org.eclipse.swt.widgets.Button; 28 import org.eclipse.swt.widgets.Composite; 29 import org.eclipse.swt.widgets.Control; 30 import org.eclipse.swt.widgets.FileDialog; 31 import org.eclipse.swt.widgets.Group; 32 import org.eclipse.swt.widgets.Label; 33 import org.eclipse.swt.widgets.Shell; 34 import org.eclipse.swt.widgets.Text; 35 36 import java.io.File; 37 38 public class SystraceOptionsDialogV1 extends TitleAreaDialog implements ISystraceOptionsDialog { 39 private static final String TITLE = "Android System Trace"; 40 private static final String DEFAULT_MESSAGE = 41 "Settings to use while capturing system level trace"; 42 private static final String DEFAULT_TRACE_FNAME = "trace.html"; //$NON-NLS-1$ 43 44 private Text mDestinationText; 45 private String mDestinationPath; 46 private Text mTraceDurationText; 47 private Text mTraceBufferSizeText; 48 49 private static String sSaveToFolder = System.getProperty("user.home"); //$NON-NLS-1$ 50 private static String sTraceDuration = ""; 51 private static String sTraceBufferSize = ""; 52 53 private Button mTraceCpuFreqBtn; 54 private Button mTraceCpuIdleBtn; 55 private Button mTraceCpuLoadBtn; 56 private Button mTraceDiskIoBtn; 57 private Button mTraceKernelWorkqueuesBtn; 58 private Button mTraceCpuSchedulerBtn; 59 60 private static boolean sTraceCpuFreq; 61 private static boolean sTraceCpuIdle; 62 private static boolean sTraceCpuLoad; 63 private static boolean sTraceDiskIo; 64 private static boolean sTraceKernelWorkqueues; 65 private static boolean sTraceCpuScheduler; 66 67 private Button mGfxTagBtn; 68 private Button mInputTagBtn; 69 private Button mViewTagBtn; 70 private Button mWebViewTagBtn; 71 private Button mWmTagBtn; 72 private Button mAmTagBtn; 73 private Button mSyncTagBtn; 74 private Button mAudioTagBtn; 75 private Button mVideoTagBtn; 76 private Button mCameraTagBtn; 77 78 private static boolean sGfxTag; 79 private static boolean sInputTag; 80 private static boolean sViewTag; 81 private static boolean sWebViewTag; 82 private static boolean sWmTag; 83 private static boolean sAmTag; 84 private static boolean sSyncTag; 85 private static boolean sAudioTag; 86 private static boolean sVideoTag; 87 private static boolean sCameraTag; 88 89 private final SystraceOptions mOptions = new SystraceOptions(); 90 91 public SystraceOptionsDialogV1(Shell parentShell) { 92 super(parentShell); 93 } 94 95 @Override 96 protected Control createDialogArea(Composite parent) { 97 setTitle(TITLE); 98 setMessage(DEFAULT_MESSAGE); 99 100 Composite c = new Composite(parent, SWT.BORDER); 101 c.setLayout(new GridLayout(3, false)); 102 c.setLayoutData(new GridData(GridData.FILL_BOTH)); 103 104 Label l = new Label(c, SWT.NONE); 105 l.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 106 l.setText("Destination File: "); 107 108 mDestinationText = new Text(c, SWT.BORDER); 109 mDestinationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 110 mDestinationText.setText(sSaveToFolder + File.separator + DEFAULT_TRACE_FNAME); 111 112 final Button browse = new Button(c, SWT.NONE); 113 browse.setText("Browse..."); 114 browse.addSelectionListener(new SelectionAdapter() { 115 @Override 116 public void widgetSelected(SelectionEvent e) { 117 String path = openBrowseDialog(browse.getShell()); 118 if (path != null) mDestinationText.setText(path); 119 } 120 }); 121 122 Label lblTraceDurationseconds = new Label(c, SWT.NONE); 123 lblTraceDurationseconds.setLayoutData( 124 new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 125 lblTraceDurationseconds.setText("Trace duration (seconds): "); 126 127 mTraceDurationText = new Text(c, SWT.BORDER); 128 mTraceDurationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); 129 mTraceDurationText.setText(sTraceDuration); 130 131 Label lblTraceBufferSize = new Label(c, SWT.NONE); 132 lblTraceBufferSize.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 133 lblTraceBufferSize.setText("Trace Buffer Size (kb): "); 134 135 mTraceBufferSizeText = new Text(c, SWT.BORDER); 136 mTraceBufferSizeText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); 137 mTraceBufferSizeText.setText(sTraceBufferSize); 138 139 Label separator = new Label(c, SWT.SEPARATOR | SWT.HORIZONTAL); 140 GridData gd = new GridData(GridData.FILL_HORIZONTAL); 141 gd.horizontalSpan = 3; 142 separator.setLayoutData(gd); 143 144 Group grpTraceEvents = new Group(c, SWT.BORDER); 145 grpTraceEvents.setLayout(new GridLayout(3, false)); 146 grpTraceEvents.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1)); 147 grpTraceEvents.setText("Trace Events"); 148 149 mTraceCpuFreqBtn = new Button(grpTraceEvents, SWT.CHECK); 150 mTraceCpuFreqBtn.setText("CPU Frequency Changes"); 151 mTraceCpuFreqBtn.setSelection(sTraceCpuFreq); 152 153 mTraceCpuIdleBtn = new Button(grpTraceEvents, SWT.CHECK); 154 mTraceCpuIdleBtn.setText("CPU Idle Events"); 155 mTraceCpuIdleBtn.setSelection(sTraceCpuIdle); 156 157 mTraceCpuLoadBtn = new Button(grpTraceEvents, SWT.CHECK); 158 mTraceCpuLoadBtn.setText("CPU Load"); 159 mTraceCpuLoadBtn.setSelection(sTraceCpuLoad); 160 161 mTraceCpuSchedulerBtn = new Button(grpTraceEvents, SWT.CHECK); 162 mTraceCpuSchedulerBtn.setText("CPU Scheduler"); 163 mTraceCpuSchedulerBtn.setSelection(sTraceCpuScheduler); 164 165 Group grpTraceRootEvents = new Group(c, SWT.BORDER); 166 grpTraceRootEvents.setLayout(new GridLayout(2, false)); 167 grpTraceRootEvents.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1)); 168 grpTraceRootEvents.setText("Trace Events that require root privileges on device"); 169 170 mTraceDiskIoBtn = new Button(grpTraceRootEvents, SWT.CHECK); 171 mTraceDiskIoBtn.setText("Disk I/O"); 172 mTraceDiskIoBtn.setSelection(sTraceDiskIo); 173 174 mTraceKernelWorkqueuesBtn = new Button(grpTraceRootEvents, SWT.CHECK); 175 mTraceKernelWorkqueuesBtn.setText("Kernel Workqueues (requires root)"); 176 mTraceKernelWorkqueuesBtn.setSelection(sTraceKernelWorkqueues); 177 178 Group grpTraceTags = new Group(c, SWT.BORDER); 179 grpTraceTags.setLayout(new GridLayout(5, false)); 180 grpTraceTags.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 3, 1)); 181 grpTraceTags.setText("Trace Tags"); 182 183 mGfxTagBtn = new Button(grpTraceTags, SWT.CHECK); 184 mGfxTagBtn.setText("gfx"); 185 mGfxTagBtn.setSelection(sGfxTag); 186 187 mInputTagBtn = new Button(grpTraceTags, SWT.CHECK); 188 mInputTagBtn.setText("input"); 189 mInputTagBtn.setSelection(sInputTag); 190 191 mViewTagBtn = new Button(grpTraceTags, SWT.CHECK); 192 mViewTagBtn.setText("view"); 193 mViewTagBtn.setSelection(sViewTag); 194 195 mWebViewTagBtn = new Button(grpTraceTags, SWT.CHECK); 196 mWebViewTagBtn.setText("webview"); 197 mWebViewTagBtn.setSelection(sWebViewTag); 198 199 mWmTagBtn = new Button(grpTraceTags, SWT.CHECK); 200 mWmTagBtn.setText("wm"); 201 mWmTagBtn.setSelection(sWmTag); 202 203 mAmTagBtn = new Button(grpTraceTags, SWT.CHECK); 204 mAmTagBtn.setText("am"); 205 mAmTagBtn.setSelection(sAmTag); 206 207 mSyncTagBtn = new Button(grpTraceTags, SWT.CHECK); 208 mSyncTagBtn.setText("sync"); 209 mSyncTagBtn.setSelection(sSyncTag); 210 211 mAudioTagBtn = new Button(grpTraceTags, SWT.CHECK); 212 mAudioTagBtn.setText("audio"); 213 mAudioTagBtn.setSelection(sAudioTag); 214 215 mVideoTagBtn = new Button(grpTraceTags, SWT.CHECK); 216 mVideoTagBtn.setText("video"); 217 mVideoTagBtn.setSelection(sVideoTag); 218 219 mCameraTagBtn = new Button(grpTraceTags, SWT.CHECK); 220 mCameraTagBtn.setText("camera"); 221 mCameraTagBtn.setSelection(sCameraTag); 222 223 Label lblTraceTagsWarning = new Label(grpTraceTags, SWT.NONE); 224 lblTraceTagsWarning.setText( 225 "Changes to trace tags will likely need a restart of the Android framework to take effect:\n" 226 + " $ adb shell stop\n" 227 + " $ adb shell start"); 228 lblTraceTagsWarning.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 5, 1)); 229 230 ModifyListener m = new ModifyListener() { 231 @Override 232 public void modifyText(ModifyEvent e) { 233 validateFields(); 234 } 235 }; 236 237 mDestinationText.addModifyListener(m); 238 mTraceBufferSizeText.addModifyListener(m); 239 mTraceDurationText.addModifyListener(m); 240 241 return c; 242 } 243 244 private void validateFields() { 245 // validate trace destination path 246 String msg = validatePath(mDestinationText.getText()); 247 if (msg != null) { 248 setErrorMessage(msg); 249 getButton(OK).setEnabled(false); 250 return; 251 } 252 253 // validate the trace duration 254 if (!validateInteger(mTraceDurationText.getText())) { 255 setErrorMessage("Trace Duration should be a valid integer (seconds)"); 256 getButton(OK).setEnabled(false); 257 return; 258 } 259 260 // validate the trace buffer size 261 if (!validateInteger(mTraceBufferSizeText.getText())) { 262 setErrorMessage("Trace Buffer Size should be a valid integer (kilobytes)"); 263 getButton(OK).setEnabled(false); 264 return; 265 } 266 267 getButton(OK).setEnabled(true); 268 setErrorMessage(null); 269 } 270 271 private boolean validateInteger(String text) { 272 if (text == null || text.isEmpty()) { 273 return true; 274 } 275 276 try { 277 Integer.parseInt(text); 278 return true; 279 } catch (NumberFormatException e) { 280 return false; 281 } 282 } 283 284 private String validatePath(String path) { 285 if (path == null || path.isEmpty()) { 286 return null; 287 } 288 289 File f = new File(path); 290 if (f.isDirectory()) { 291 return String.format("The path '%s' points to a folder", path); 292 } 293 294 if (!f.exists()) { // if such a file doesn't exist, make sure the parent folder is valid 295 if (!f.getParentFile().isDirectory()) { 296 return String.format("That path '%s' is not a valid folder.", f.getParent()); 297 } 298 } 299 300 return null; 301 } 302 303 private String openBrowseDialog(Shell parentShell) { 304 FileDialog fd = new FileDialog(parentShell, SWT.SAVE); 305 306 fd.setText("Save To"); 307 fd.setFileName(DEFAULT_TRACE_FNAME); 308 309 fd.setFilterPath(sSaveToFolder); 310 fd.setFilterExtensions(new String[] { "*.html" }); //$NON-NLS-1$ 311 312 String fname = fd.open(); 313 if (fname == null || fname.trim().length() == 0) { 314 return null; 315 } 316 317 sSaveToFolder = fd.getFilterPath(); 318 return fname; 319 } 320 321 @Override 322 protected void okPressed() { 323 mDestinationPath = mDestinationText.getText().trim(); 324 325 sTraceDuration = mTraceDurationText.getText(); 326 if (!sTraceDuration.isEmpty()) { 327 mOptions.mTraceDuration = Integer.parseInt(sTraceDuration); 328 } 329 330 sTraceBufferSize = mTraceBufferSizeText.getText(); 331 if (!sTraceBufferSize.isEmpty()) { 332 mOptions.mTraceBufferSize = Integer.parseInt(sTraceBufferSize); 333 } 334 335 mOptions.mTraceCpuFreq = mTraceCpuFreqBtn.getSelection(); 336 mOptions.mTraceCpuIdle = mTraceCpuIdleBtn.getSelection(); 337 mOptions.mTraceCpuLoad = mTraceCpuLoadBtn.getSelection(); 338 mOptions.mTraceDiskIo = mTraceDiskIoBtn.getSelection(); 339 mOptions.mTraceKernelWorkqueues = mTraceKernelWorkqueuesBtn.getSelection(); 340 mOptions.mTraceCpuScheduler = mTraceCpuSchedulerBtn.getSelection(); 341 342 if (mGfxTagBtn.getSelection()) mOptions.enableTag(SystraceOptions.TAG_GFX); 343 if (mInputTagBtn.getSelection()) mOptions.enableTag(SystraceOptions.TAG_INPUT); 344 if (mViewTagBtn.getSelection()) mOptions.enableTag(SystraceOptions.TAG_VIEW); 345 if (mWebViewTagBtn.getSelection()) mOptions.enableTag(SystraceOptions.TAG_WEBVIEW); 346 if (mWmTagBtn.getSelection()) mOptions.enableTag(SystraceOptions.TAG_WM); 347 if (mAmTagBtn.getSelection()) mOptions.enableTag(SystraceOptions.TAG_AM); 348 if (mSyncTagBtn.getSelection()) mOptions.enableTag(SystraceOptions.TAG_SYNC); 349 if (mAudioTagBtn.getSelection()) mOptions.enableTag(SystraceOptions.TAG_AUDIO); 350 if (mVideoTagBtn.getSelection()) mOptions.enableTag(SystraceOptions.TAG_VIDEO); 351 if (mCameraTagBtn.getSelection()) mOptions.enableTag(SystraceOptions.TAG_CAMERA); 352 353 // save current selections to be restored if the dialog is invoked again 354 sTraceCpuFreq = mTraceCpuFreqBtn.getSelection(); 355 sTraceCpuIdle = mTraceCpuIdleBtn.getSelection(); 356 sTraceCpuLoad = mTraceCpuLoadBtn.getSelection(); 357 sTraceDiskIo = mTraceDiskIoBtn.getSelection(); 358 sTraceKernelWorkqueues = mTraceKernelWorkqueuesBtn.getSelection(); 359 sTraceCpuScheduler = mTraceCpuSchedulerBtn.getSelection(); 360 361 sGfxTag = mGfxTagBtn.getSelection(); 362 sInputTag = mInputTagBtn.getSelection(); 363 sViewTag = mViewTagBtn.getSelection(); 364 sWebViewTag = mWebViewTagBtn.getSelection(); 365 sWmTag = mWmTagBtn.getSelection(); 366 sAmTag = mAmTagBtn.getSelection(); 367 sSyncTag = mSyncTagBtn.getSelection(); 368 sAudioTag = mAudioTagBtn.getSelection(); 369 sVideoTag = mVideoTagBtn.getSelection(); 370 sCameraTag = mCameraTagBtn.getSelection(); 371 372 super.okPressed(); 373 } 374 375 @Override 376 public SystraceOptions getSystraceOptions() { 377 return mOptions; 378 } 379 380 @Override 381 public String getTraceFilePath() { 382 return mDestinationPath; 383 } 384 385 private class SystraceOptions implements ISystraceOptions { 386 // This list is based on the tags in frameworks/native/include/utils/Trace.h 387 private static final int TAG_GFX = 1 << 1; 388 private static final int TAG_INPUT = 1 << 2; 389 private static final int TAG_VIEW = 1 << 3; 390 private static final int TAG_WEBVIEW = 1 << 4; 391 private static final int TAG_WM = 1 << 5; 392 private static final int TAG_AM = 1 << 6; 393 private static final int TAG_SYNC = 1 << 7; 394 private static final int TAG_AUDIO = 1 << 8; 395 private static final int TAG_VIDEO = 1 << 9; 396 private static final int TAG_CAMERA = 1 << 10; 397 398 private int mTraceBufferSize; 399 private int mTraceDuration; 400 401 private boolean mTraceCpuFreq; 402 private boolean mTraceCpuIdle; 403 private boolean mTraceCpuLoad; 404 private boolean mTraceDiskIo; 405 private boolean mTraceKernelWorkqueues; 406 private boolean mTraceCpuScheduler; 407 408 private int mTag; 409 410 private void enableTag(int tag) { 411 mTag |= tag; 412 } 413 414 @Override 415 public String getTags() { 416 return mTag == 0 ? null : "0x" + Integer.toHexString(mTag); 417 } 418 419 @Override 420 public String getOptions() { 421 StringBuilder sb = new StringBuilder(20); 422 423 if (mTraceCpuFreq) sb.append("-f "); //$NON-NLS-1$ 424 if (mTraceCpuIdle) sb.append("-i "); //$NON-NLS-1$ 425 if (mTraceCpuLoad) sb.append("-l "); //$NON-NLS-1$ 426 if (mTraceDiskIo) sb.append("-d "); //$NON-NLS-1$ 427 if (mTraceKernelWorkqueues) sb.append("-w "); //$NON-NLS-1$ 428 if (mTraceCpuScheduler) sb.append("-s "); //$NON-NLS-1$ 429 430 if (mTraceDuration > 0) { 431 sb.append("-t"); //$NON-NLS-1$ 432 sb.append(mTraceDuration); 433 sb.append(' '); 434 } 435 436 if (mTraceBufferSize > 0) { 437 sb.append("-b "); //$NON-NLS-1$ 438 sb.append(mTraceBufferSize); 439 sb.append(' '); 440 } 441 442 return sb.toString().trim(); 443 } 444 } 445 } 446