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