1<!DOCTYPE html> 2<!-- 3Copyright (c) 2015 The Chromium Authors. All rights reserved. 4Use of this source code is governed by a BSD-style license that can be 5found in the LICENSE file. 6--> 7 8<link rel="import" href="/tracing/extras/importer/linux_perf/parser.html"> 9 10<script> 11'use strict'; 12 13/** 14 * @fileoverview Parses Binder events 15 */ 16tr.exportTo('tr.e.importer.linux_perf', function() { 17 var ColorScheme = tr.b.ColorScheme; 18 var Parser = tr.e.importer.linux_perf.Parser; 19 20 // Matches binder transactions: 21 // transaction=%d dest_node=%d dest_proc=%d dest_thread=%d reply=%d flags=0x%x 22 // code=0x%x 23 var binderTransRE = new RegExp('transaction=(\\d+) dest_node=(\\d+) ' + 24 'dest_proc=(\\d+) dest_thread=(\\d+) ' + 25 'reply=(\\d+) flags=(0x[0-9a-fA-F]+) ' + 26 'code=(0x[0-9a-fA-F]+)'); 27 28 var binderTransReceivedRE = /transaction=(\d+)/; 29 30 function isBinderThread(name) { 31 return (name.indexOf('Binder') > -1); 32 } 33 34 // Taken from kernel source: include/uapi/linux/android/binder.h. 35 var TF_ONE_WAY = 0x01; 36 var TF_ROOT_OBJECT = 0x04; 37 var TF_STATUS_CODE = 0x08; 38 var TF_ACCEPT_FDS = 0x10; 39 var NO_FLAGS = 0; 40 41 function binderFlagsToHuman(num) { 42 var flag = parseInt(num, 16); 43 var str = ''; 44 45 if (flag & TF_ONE_WAY) 46 str += 'this is a one-way call: async, no return; '; 47 if (flag & TF_ROOT_OBJECT) 48 str += 'contents are the components root object; '; 49 if (flag & TF_STATUS_CODE) 50 str += 'contents are a 32-bit status code; '; 51 if (flag & TF_ACCEPT_FDS) 52 str += 'allow replies with file descriptors; '; 53 if (flag === NO_FLAGS) 54 str += 'No Flags Set'; 55 56 return str; 57 } 58 59 function isReplyToOrigin(calling, called) { 60 return (called.dest_proc === calling.calling_pid || 61 called.dest_thread === calling.calling_pid); 62 } 63 64 function binderCodeToHuman(code) { 65 return 'Java Layer Dependent'; 66 } 67 68 function doInternalSlice(trans, slice, ts) { 69 if (slice.subSlices.length !== 0) { 70 /* We want to make sure we keep moving the small slice to the end of 71 the big slice or else the arrows will not point to the end. 72 */ 73 slice.subSlices[0].start = ts; 74 return slice.subSlices[0]; 75 } 76 var kthread = trans.calling_kthread.thread; 77 var internal_slice = kthread.sliceGroup.pushCompleteSlice('binder', 78 slice.title, 79 ts, .001, 0, 0, 80 slice.args); 81 82 internal_slice.title = slice.title; 83 internal_slice.id = slice.id; 84 internal_slice.colorId = slice.colorId; 85 slice.subSlices.push(internal_slice); 86 return internal_slice; 87 } 88 89 function generateBinderArgsForSlice(trans, c_threadName) { 90 return { 91 'Transaction Id': trans.transaction_key, 92 'Destination Node': trans.dest_node, 93 'Destination Process': trans.dest_proc, 94 'Destination Thread': trans.dest_thread, 95 'Destination Name': c_threadName, 96 'Reply transaction?': trans.is_reply_transaction, 97 'Flags': trans.flags + ' ' + 98 binderFlagsToHuman(trans.flags), 99 100 'Code': trans.code + ' ' + 101 binderCodeToHuman(trans.code), 102 103 'Calling PID': trans.calling_pid, 104 'Calling tgid': trans.calling_kthread.thread.parent.pid 105 }; 106 } 107 108 /** @constructor */ 109 function BinderTransaction(events, calling_pid, calling_ts, calling_kthread) { 110 this.transaction_key = parseInt(events[1]); 111 this.dest_node = parseInt(events[2]); 112 this.dest_proc = parseInt(events[3]); 113 this.dest_thread = parseInt(events[4]); 114 this.is_reply_transaction = parseInt(events[5]) === 1 ? true : false; 115 this.expect_reply = ((this.is_reply_transaction === false) && 116 (parseInt(events[6], 16) & TF_ONE_WAY) === 0); 117 118 this.flags = events[6]; 119 this.code = events[7]; 120 this.calling_pid = calling_pid; 121 this.calling_ts = calling_ts; 122 this.calling_kthread = calling_kthread; 123 } 124 125 126 /** @constructor */ 127 function BinderParser(importer) { 128 Parser.call(this, importer); 129 importer.registerEventHandler('binder_locked', 130 BinderParser.prototype. 131 binderLocked.bind(this)); 132 importer.registerEventHandler('binder_unlock', 133 BinderParser.prototype. 134 binderUnlock.bind(this)); 135 importer.registerEventHandler('binder_lock', 136 BinderParser.prototype.binderLock.bind(this)); 137 importer.registerEventHandler('binder_transaction', 138 BinderParser.prototype. 139 binderTransaction.bind(this)); 140 importer.registerEventHandler('binder_transaction_received', 141 BinderParser.prototype. 142 binderTransactionReceived.bind(this)); 143 144 this.model_ = importer.model; 145 this.kthreadlookup = {}; 146 this.importer_ = importer; 147 this.transWaitingRecv = {}; 148 this.syncTransWaitingCompletion = {}; 149 this.recursiveSyncTransWaitingCompletion_ByPID = {}; 150 this.receivedTransWaitingConversion = {}; 151 } 152 153 BinderParser.prototype = { 154 __proto__: Parser.prototype, 155 156 binderLock: function(eventName, cpuNumber, pid, ts, eventBase) { 157 var tgid = parseInt(eventBase.tgid); 158 this.doNameMappings(pid, tgid, eventName.threadName); 159 160 var kthread = this.importer_. 161 getOrCreateBinderKernelThread(eventBase.threadName, tgid, pid); 162 163 kthread.binderAttemptLockTS = ts; 164 kthread.binderOpenTsA = ts; 165 return true; 166 }, 167 168 binderLocked: function(eventName, cpuNumber, pid, ts, eventBase) { 169 var binder_thread = isBinderThread(eventBase.threadName); 170 var tgid, name; 171 var as_slice; 172 var need_push = false; 173 var kthread, rthread; 174 175 tgid = parseInt(eventBase.tgid); 176 name = eventBase.threadName; 177 178 kthread = this.importer_. 179 getOrCreateBinderKernelThread(eventBase.threadName, tgid, pid); 180 181 this.doNameMappings(pid, tgid, name); 182 183 rthread = kthread.thread; 184 kthread.binderLockAquiredTS = ts; 185 186 if (kthread.binderAttemptLockTS === undefined) 187 return false; 188 189 var args = this.generateArgsForSlice(tgid, pid, name, kthread); 190 rthread.sliceGroup.pushCompleteSlice('binder', 'binder lock waiting', 191 kthread.binderAttemptLockTS, 192 ts - kthread.binderAttemptLockTS, 193 0, 0, args); 194 195 kthread.binderAttemptLockTS = undefined; 196 return true; 197 }, 198 199 binderUnlock: function(eventName, cpuNumber, pid, ts, eventBase) { 200 var tgid = parseInt(eventBase.tgid); 201 var kthread = this.importer_. 202 getOrCreateBinderKernelThread( 203 eventBase.threadName, tgid, pid); 204 205 if (kthread.binderLockAquiredTS === undefined) 206 return false; 207 208 var args = this.generateArgsForSlice(tgid, pid, eventBase.threadName, 209 kthread); 210 kthread.thread.sliceGroup.pushCompleteSlice( 211 'binder', 212 'binder lock held', 213 kthread.binderLockAquiredTS, 214 ts - kthread.binderLockAquiredTS, 215 0, 0, args); 216 217 kthread.binderLockAquiredTS = undefined; 218 return true; 219 }, 220 221 /** There are a few transaction status changes that signify 222 * progress through a binder transaction: 223 * 224 * Case One: Sync transaction. 225 * Thread A calls a blocking function on Thread B. We receive a 226 * binder_transaction msg From thread A stating that it is going to Call 227 * thread B. We create a slice and a binder object for this transaction and 228 * add it to addTransactionWaitingForRecv(transaction key, binder object) 229 * This notifies thread B and passes the slice, binder object and time 230 * stamp. 231 * 232 * Case Two: Async transaction. 233 * Thread A calls an async function on Thread B. Like above we receive a 234 * binder_transaction message, but the flags differ from above. The 235 * TF_ONEWAY flags are set so we know that when Thread B gets the 236 * binder_transaction_received with the same transaciton key the total 237 * transaction is complete. 238 * 239 * Case Three: 'Prior_receive' 240 * Prior_receive occurs when the thread being called (think A calls B), 241 * receives a binder_transaction_received message, but cannot correlate it 242 * to any current outstanding recursive transactions. That means the 243 * message it just received is the start of some communication, not some 244 * ongoing communication. 245 * Once the execution flow has been passed to thread B, from A: 246 * Thread B enters binder_transaction_received() we see that Thread A 247 * had notified us that it sent us a message by calling 248 * getTransactionWaitingForRecv(transaction key); 249 * What can happen now is either this was a simple Call reply, 250 * or this is a call -> recursion -> reply. We call modelPriorReceive() 251 * which sets up the slices accordingly. 252 * If this is a call -> recursion -> reply 253 * we will go to case 4 by calling addRecursiveSyncTransNeedingCompletion() 254 * The function takes B's PID, the binder object from A and the current 255 * binder object from B. This function adds outstanding non-complete 256 * transactions to a stack on thread B. 257 * 258 * Case Four: 'recursive_trans' 259 * This case follows Like above: 260 * A sent binder_transaction 261 * B got binder_transaction_received 262 * B instead of replying to A can Call C or call 'into' A, ie recursion 263 * Case four also deals with setting up a large slice to 'contain' 264 * all the recursive transactions that happen until B finally replies to 265 * A. 266 * 267 * 268 * An example: A-> B-> C-> B-> A 269 * 270 * (1) A starts a synchronous transaction to B. 271 * (2) A enters binderTransaction() event handler, hits the else statement 272 * (3) A calls addTransactionWaitingForRecv(trans key, object) to notify 273 * Thread B. 274 * (4) B Enters binderTransactionReceived(). 275 * (5) B hits the second if after calling 276 * getTransactionWaitingForRecv(trans key) 277 * This function returns us the object set up in step (3). 278 * (6) This is not an async transaction, B calls 279 * setCurrentReceiveOnPID(B's PID, [ts for (4), object from (3)]). 280 * 281 * (7) B enters binderTransaction() event handler, first if triggers after 282 * calling getPriorReceiveOnPID(B's PID) the tuple from (6) is returned. 283 * 284 * (8) Execution enters modelPriorReceive(). 285 * (8a) A slice is setup for this binder transaction in B's timeline. 286 * (9) This is not a reply to thread A, B is going to call Thread C. 287 * (10) else statement is hit. 288 * (11) We set the tile from (8a) to be binder_reply this is the 289 * 'containg slice' for the recursion 290 * (12) We create a new slice 'binder_transaction' this slice is the 291 * recursive slice that will have arrows to Thread C's slice. 292 * (13) addRecursiveSyncTransNeedingCompletion(B's PID, 293 * [obj from (3), obj from 7]) 294 * this sets up notification that B's pid has outstanding recursive 295 * transactions that need to be completed. 296 * (14) B notifies C that a transaction is waiting for it by calling 297 * addTransactionWaitingForRecv like in step (3). 298 * (15) C enters binderTransactionReceived() step 5 6 7 8 8a happen, but in 299 * the context of Thread C. 300 * (16) C is in modelPriorReceive(), it hits the first if statement, 301 * this transaction _IS_ a reply, and it is a reply to B. 302 * (17) C calls addSyncTransNeedingCompletion(trans key, 303 * [object from(3), object from 15-5]) 304 * (18) B enters binderTransactionReceived() hits the first if after calling 305 * getSyncTransNeedingCompletion(trans key from (17)) the tuple from 306 * (17) gets returned. 307 * 308 * (19) B scales up the slice created in (12) and sets up flows from 15-8a 309 * slice. 310 * (20) B enters BinderTransaction() event handler and the second if is hit 311 * after calling getRecursiveTransactionNeedingCompletion(B's pid). 312 * (21) modelRecursiveTransactions() gets called, first if executes. 313 * (22) slice durations are fixed up. 314 * (23) B notifies A via 315 * addSyncTransNeedingCompletion(trans key, binder obj from 8a). 316 * (24) B deletes the outstanding asynctrans via 317 ( removeRecursiveTransaction(B's pid). 318 * (25) A enters binderTransactionReceived() event handler and finishes up 319 * some flows, and slices. 320 */ 321 binderTransaction: function(eventName, cpuNumber, pid, ts, eventBase) { 322 var event = binderTransRE.exec(eventBase.details); 323 if (event === undefined) 324 return false; 325 326 var tgid = parseInt(eventBase.tgid); 327 328 this.doNameMappings(pid, tgid, eventBase.threadName); 329 330 var kthread; 331 kthread = this.importer_. 332 getOrCreateBinderKernelThread(eventBase.threadName, tgid, pid); 333 334 var trans = new BinderTransaction(event, pid, ts, kthread); 335 var args = generateBinderArgsForSlice(trans, eventBase.threadName); 336 /** 337 * This thread previously ack'd the transaction with a 338 * transaction_received. That means someone sent us a message we processed 339 * it and are now sending a transaction. 340 * The transaction could be a response, or it could be recursive. 341 */ 342 var prior_receive = this.getPriorReceiveOnPID(pid); 343 344 if (prior_receive !== false) { 345 return this.modelPriorReceive(prior_receive, ts, pid, tgid, kthread, 346 trans, args, event); 347 } 348 /** 349 * This Thread has an already established recursive slice. We will now 350 * either complete the entire transaction, OR do more recursive calls. 351 */ 352 var recursive_trans = this.getRecursiveTransactionNeedingCompletion(pid); 353 354 if (recursive_trans !== false) 355 return this.modelRecursiveTransactions(recursive_trans, ts, pid, 356 kthread, trans, args); 357 358 /** 359 * Start of a Transaction. This thread is the initiator of either a call 360 * response, an async call -> ack, or a call -> recursion -> response. 361 * Note, we put a fake duration into this slice and patch it up later. 362 */ 363 var slice = kthread.thread.sliceGroup.pushCompleteSlice('binder', 364 '', ts, .03, 0, 0, args); 365 366 slice.colorId = ColorScheme.getColorIdForGeneralPurposeString( 367 ts.toString()); 368 trans.slice = slice; 369 370 if (trans.expect_reply) 371 slice.title = 'binder transaction'; 372 else 373 slice.title = 'binder transaction async'; 374 375 this.addTransactionWaitingForRecv(trans.transaction_key, trans); 376 377 return true; 378 }, 379 380 binderTransactionReceived: function(eventName, cpuNumber, pid, ts, 381 eventBase) { 382 var event = binderTransReceivedRE.exec(eventBase.details); 383 384 if (event === undefined) 385 return false; 386 387 var transactionkey = parseInt(event[1]); 388 var tgid = parseInt(eventBase.tgid); 389 var kthread; 390 kthread = this.importer_. 391 getOrCreateBinderKernelThread(eventBase.threadName, tgid, pid); 392 393 var syncComplete = this.getSyncTransNeedsCompletion(transactionkey); 394 395 if (syncComplete !== false) { 396 /* This recv is the completion of a synchronous transaction. 397 * We need to scale the slice up to the current ts and finish 398 * creating some flows. 399 */ 400 var sync_trans = syncComplete[0]; 401 var sync_slice = sync_trans.slice; 402 var response_trans = syncComplete[1]; 403 var response_slice = response_trans.slice; 404 405 sync_slice.duration = ts - sync_slice.start; 406 /** These calls are a little hack that places a very small slice at 407 * the end of the sync slice and the response slice. This allows us 408 * to hook flow events (arrows) from the start to the end of the 409 * slices. 410 */ 411 var sync_internal = doInternalSlice(sync_trans, sync_slice, ts); 412 var response_ts = response_slice.start + response_slice.duration; 413 var response_internal = doInternalSlice(response_trans, 414 response_slice, response_ts); 415 416 if (response_slice.outFlowEvents.length === 0 || 417 sync_slice.inFlowEvents.length === 0) { 418 var flow = this.generateFlow(response_internal, sync_internal, 419 response_trans, sync_trans); 420 421 sync_slice.inFlowEvents.push(flow); 422 response_slice.outFlowEvents.push(flow); 423 this.model_.flowEvents.push(flow); 424 } 425 // Move flow arrows -- but not the first one. 426 for (var i = 1; i < sync_slice.inFlowEvents.length; i++) { 427 sync_slice.inFlowEvents[i].duration = 428 ts - sync_slice.inFlowEvents[i].start; 429 } 430 return true; 431 } 432 433 var tr_for_recv = this.getTransactionWaitingForRecv(transactionkey); 434 435 if (tr_for_recv !== false) { 436 if (!tr_for_recv.expect_reply) { 437 // This is an async call place an Async slice. 438 var args = generateBinderArgsForSlice(tr_for_recv, 439 eventBase.threadName); 440 var slice = kthread.thread.sliceGroup. 441 pushCompleteSlice('binder', 442 'binder Async recv', 443 ts, .03, 0, 0, 444 args); 445 446 var fake_event = [0, 0, 0, 0, 0, 0, 0]; 447 var fake_trans = new BinderTransaction(fake_event, pid, ts, kthread); 448 var flow = this.generateFlow(tr_for_recv.slice, slice, 449 tr_for_recv, fake_trans); 450 451 this.model_.flowEvents.push(flow); 452 tr_for_recv.slice.title = 'binder transaction async'; 453 tr_for_recv.slice.duration = .03; 454 return true; 455 } 456 // Setup prior receive. 457 tr_for_recv.slice.title = 'binder transaction'; 458 this.setCurrentReceiveOnPID(pid, [ts, tr_for_recv]); 459 return true; 460 } 461 /** This case is when we received an ack for a transaction we have 462 * never seen before. This usually happens at the start of a trace. 463 * We will get incomplete transactions that started before started 464 * tracing. Just discard them. 465 */ 466 return false; 467 }, 468 469 // helper functions 470 modelRecursiveTransactions: function(recursive_trans, ts, pid, kthread, 471 trans, args) { 472 473 var recursive_slice = recursive_trans[1].slice; 474 var orig_slice = recursive_trans[0].slice; 475 recursive_slice.duration = ts - recursive_slice.start; 476 trans.slice = recursive_slice; 477 478 if (trans.is_reply_transaction) { 479 /* Case one: 480 * This transaction is finally the reply of the recursion. 481 */ 482 orig_slice.duration = ts - orig_slice.start; 483 this.addSyncTransNeedingCompletion(trans.transaction_key, 484 recursive_trans); 485 486 if (isReplyToOrigin(recursive_trans[0], trans)) 487 this.removeRecursiveTransaction(pid); 488 } else { 489 /** 490 * Case two: 491 * This transaction is more recursive calls. 492 * This is a nested call within an already started transaction, 493 * it can either be a async or a normal sync transaction. 494 */ 495 var slice = kthread.thread.sliceGroup.pushCompleteSlice('binder', 496 '' , ts, .03, 0, 497 0, args); 498 499 trans.slice = slice; 500 this.addTransactionWaitingForRecv(trans.transaction_key, trans); 501 } 502 return true; 503 }, 504 505 modelPriorReceive: function(prior_receive, ts, pid, tgid, kthread, trans, 506 args, event) { 507 var callee_slice = prior_receive[1].slice; 508 var callee_trans = prior_receive[1]; 509 var recv_ts = prior_receive[0]; 510 var slice = kthread.thread.sliceGroup.pushCompleteSlice('binder', 511 '', recv_ts, ts - recv_ts, 0, 0, args); 512 513 var flow = this.generateFlow(callee_slice, slice, callee_trans, trans); 514 this.model_.flowEvents.push(flow); 515 trans.slice = slice; 516 517 if (trans.is_reply_transaction) { 518 /* This is a response to a synchronous or a recursive sync 519 * transaction. 520 */ 521 slice.title = 'binder reply'; 522 /* Notify this transaction key that when it recv's it is completing 523 * a sync transaction. 524 */ 525 this.addSyncTransNeedingCompletion(trans.transaction_key, 526 [callee_trans, trans]); 527 } else { 528 /** 529 * Recursive calls and or calls around, either way it's not 530 * going to complete a transaction. 531 */ 532 slice.title = 'binder reply'; 533 /* Since this is a recursive transaction we want to create the main 534 * large slice which will contain all these recursive transactions. 535 * For that we created the main slice above and this is a recursive 536 * transaction that will be placed right below it. Note, that this 537 * is only for the first recursive transaction. If more come they will 538 * be handled below in the getRecursiveTransactionNeedingCompletion 539 */ 540 var trans1 = new BinderTransaction(event, pid, ts, kthread); 541 542 slice = kthread.thread.sliceGroup. 543 pushCompleteSlice('binder', 544 'binder transaction', 545 recv_ts, 546 (ts - recv_ts), 0, 547 0, args); 548 549 /* could be a async trans if so set the length to be a small one */ 550 if (!trans.expect_reply) { 551 slice.title = 'binder transaction async'; 552 slice.duration = .03; 553 } else { 554 /* stupid hack to stop merging of AIDL slices and 555 * this slice. This is currently disabled, if AIDL tracing is on we 556 * will see merging of this slice and the AIDL slice. Once upstream 557 * has a solution for flow events to be placed in the middle of 558 * slices this part can be fixed. 559 * 560 * This is commented out because AIDL tracing doesn't exit yet. 561 */ 562 //slice.start += .15; 563 } 564 trans1.slice = slice; 565 this.addRecursiveSyncTransNeedingCompletion(pid, 566 [callee_trans, trans]); 567 this.addTransactionWaitingForRecv(trans.transaction_key, trans1); 568 } 569 return true; 570 }, 571 572 getRecursiveTransactionNeedingCompletion: function(pid) { 573 if (this.recursiveSyncTransWaitingCompletion_ByPID[pid] === undefined) 574 return false; 575 576 var len = this.recursiveSyncTransWaitingCompletion_ByPID[pid].length; 577 if (len === 0) 578 return false; 579 580 return this.recursiveSyncTransWaitingCompletion_ByPID[pid][len - 1]; 581 }, 582 583 addRecursiveSyncTransNeedingCompletion: function(pid, tuple) { 584 if (this.recursiveSyncTransWaitingCompletion_ByPID[pid] === undefined) 585 this.recursiveSyncTransWaitingCompletion_ByPID[pid] = []; 586 587 this.recursiveSyncTransWaitingCompletion_ByPID[pid].push(tuple); 588 }, 589 590 removeRecursiveTransaction: function(pid) { 591 var len = this.recursiveSyncTransWaitingCompletion_ByPID[pid].length; 592 if (len === 0) { 593 delete this.recursiveSyncTransWaitingCompletion_ByPID[pid]; 594 return; 595 } 596 597 this.recursiveSyncTransWaitingCompletion_ByPID[pid].splice(len - 1, 1); 598 }, 599 600 setCurrentReceiveOnPID: function(pid, tuple) { 601 if (this.receivedTransWaitingConversion[pid] === undefined) { 602 this.receivedTransWaitingConversion[pid] = []; 603 } 604 this.receivedTransWaitingConversion[pid].push(tuple); 605 }, 606 607 getPriorReceiveOnPID: function(pid) { 608 if (this.receivedTransWaitingConversion[pid] === undefined) 609 return false; 610 611 var len = this.receivedTransWaitingConversion[pid].length; 612 if (len === 0) 613 return false; 614 615 return this.receivedTransWaitingConversion[pid].splice(len - 1, 1)[0]; 616 }, 617 618 addSyncTransNeedingCompletion: function(transactionkey, tuple) { 619 var dict = this.syncTransWaitingCompletion; 620 dict[transactionkey] = tuple; 621 }, 622 623 getSyncTransNeedsCompletion: function(transactionkey) { 624 var ret = this.syncTransWaitingCompletion[transactionkey]; 625 if (ret === undefined) 626 return false; 627 628 delete this.syncTransWaitingCompletion[transactionkey]; 629 return ret; 630 }, 631 632 getTransactionWaitingForRecv: function(transactionkey) { 633 var ret = this.transWaitingRecv[transactionkey]; 634 if (ret === undefined) 635 return false; 636 637 delete this.transWaitingRecv[transactionkey]; 638 return ret; 639 }, 640 641 addTransactionWaitingForRecv: function(transactionkey, transaction) { 642 this.transWaitingRecv[transactionkey] = transaction; 643 }, 644 645 generateFlow: function(from, to, from_trans, to_trans) { 646 var title = 'Transaction from : ' + 647 this.pid2name(from_trans.calling_pid) + 648 ' From PID: ' + from_trans.calling_pid + ' to pid: ' + 649 to_trans.calling_pid + 650 ' Thread Name: ' + this.pid2name(to_trans.calling_pid); 651 652 var ts = from.start; 653 var flow = new tr.model.FlowEvent('binder', 'binder', 654 title, 1, ts, []); 655 flow.startSlice = from; 656 flow.endSlice = to; 657 flow.start = from.start; 658 flow.duration = to.start - ts; 659 660 from.outFlowEvents.push(flow); 661 to.inFlowEvents.push(flow); 662 663 return flow; 664 }, 665 666 generateArgsForSlice: function(tgid, pid, name, kthread) { 667 return { 668 'Thread Name': name, 669 'pid': pid, 670 'gid': tgid 671 }; 672 }, 673 674 pid2name: function(pid) { 675 return this.kthreadlookup[pid]; 676 }, 677 678 doNameMappings: function(pid, tgid, name) { 679 this.registerPidName(pid, name); 680 this.registerPidName(tgid, name); 681 }, 682 683 registerPidName: function(pid, name) { 684 if (this.pid2name(pid) === undefined) 685 this.kthreadlookup[pid] = name; 686 } 687 }; 688 689 Parser.register(BinderParser); 690 return { 691 BinderParser: BinderParser 692 }; 693}); 694</script> 695