Merge changes from topic 'binder_tests_aosp'

* changes:
  Add test to check buffer hdr not in user space
  Add test for death notification workqueue.
  Fix percentile calculations
  Refine the binder latency test
  Add options to specify payload size and use client/server pairs
  Add binder test for bug 30445380
  binder: tests: Check that cookie and binder high bits are zero
  binder: tests: Fix warnings
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 54e12b6..c8e478a 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -32,6 +32,13 @@
 
 using namespace android;
 
+static ::testing::AssertionResult IsPageAligned(void *buf) {
+    if (((unsigned long)buf & ((unsigned long)PAGE_SIZE - 1)) == 0)
+        return ::testing::AssertionSuccess();
+    else
+        return ::testing::AssertionFailure() << buf << " is not page aligned";
+}
+
 static testing::Environment* binder_env;
 static char *binderservername;
 static char *binderserversuffix;
@@ -44,7 +51,9 @@
     BINDER_LIB_TEST_REGISTER_SERVER,
     BINDER_LIB_TEST_ADD_SERVER,
     BINDER_LIB_TEST_CALL_BACK,
+    BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF,
     BINDER_LIB_TEST_NOP_CALL_BACK,
+    BINDER_LIB_TEST_GET_SELF_TRANSACTION,
     BINDER_LIB_TEST_GET_ID_TRANSACTION,
     BINDER_LIB_TEST_INDIRECT_TRANSACTION,
     BINDER_LIB_TEST_SET_ERROR_TRANSACTION,
@@ -56,6 +65,7 @@
     BINDER_LIB_TEST_EXIT_TRANSACTION,
     BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION,
     BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION,
+    BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
 };
 
 pid_t start_server_process(int arg2)
@@ -263,17 +273,23 @@
             pthread_mutex_unlock(&m_waitMutex);
             return ret;
         }
+        pthread_t getTriggeringThread()
+        {
+            return m_triggeringThread;
+        }
     protected:
         void triggerEvent(void) {
             pthread_mutex_lock(&m_waitMutex);
             pthread_cond_signal(&m_waitCond);
             m_eventTriggered = true;
+            m_triggeringThread = pthread_self();
             pthread_mutex_unlock(&m_waitMutex);
         };
     private:
         pthread_mutex_t m_waitMutex;
         pthread_cond_t m_waitCond;
         bool m_eventTriggered;
+        pthread_t m_triggeringThread;
 };
 
 class BinderLibTestCallBack : public BBinder, public BinderLibTestEvent
@@ -281,6 +297,7 @@
     public:
         BinderLibTestCallBack()
             : m_result(NOT_ENOUGH_DATA)
+            , m_prev_end(NULL)
         {
         }
         status_t getResult(void)
@@ -300,12 +317,35 @@
                 m_result = data.readInt32();
                 triggerEvent();
                 return NO_ERROR;
+            case BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF: {
+                sp<IBinder> server;
+                int ret;
+                const uint8_t *buf = data.data();
+                size_t size = data.dataSize();
+                if (m_prev_end) {
+                    /* 64-bit kernel needs at most 8 bytes to align buffer end */
+                    EXPECT_LE((size_t)(buf - m_prev_end), (size_t)8);
+                } else {
+                    EXPECT_TRUE(IsPageAligned((void *)buf));
+                }
+
+                m_prev_end = buf + size + data.objectsCount() * sizeof(binder_size_t);
+
+                if (size > 0) {
+                    server = static_cast<BinderLibTestEnv *>(binder_env)->getServer();
+                    ret = server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION,
+                                           data, reply);
+                    EXPECT_EQ(NO_ERROR, ret);
+                }
+                return NO_ERROR;
+            }
             default:
                 return UNKNOWN_TRANSACTION;
             }
         }
 
         status_t m_result;
+        const uint8_t *m_prev_end;
 };
 
 class TestDeathRecipient : public IBinder::DeathRecipient, public BinderLibTestEvent
@@ -389,7 +429,7 @@
 
     ret = reply.readInt32(&count);
     ASSERT_EQ(NO_ERROR, ret);
-    EXPECT_EQ(ARRAY_SIZE(serverId), count);
+    EXPECT_EQ(ARRAY_SIZE(serverId), (size_t)count);
 
     for (size_t i = 0; i < (size_t)count; i++) {
         BinderLibTestBundle replyi(&reply);
@@ -439,7 +479,7 @@
 
     ret = reply.readInt32(&count);
     ASSERT_EQ(NO_ERROR, ret);
-    EXPECT_EQ(ARRAY_SIZE(serverId), count);
+    EXPECT_EQ(ARRAY_SIZE(serverId), (size_t)count);
 
     for (size_t i = 0; i < (size_t)count; i++) {
         int32_t counti;
@@ -604,6 +644,65 @@
     }
 }
 
+TEST_F(BinderLibTest, DeathNotificationThread)
+{
+    status_t ret;
+    sp<BinderLibTestCallBack> callback;
+    sp<IBinder> target = addServer();
+    ASSERT_TRUE(target != NULL);
+    sp<IBinder> client = addServer();
+    ASSERT_TRUE(client != NULL);
+
+    sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient();
+
+    ret = target->linkToDeath(testDeathRecipient);
+    EXPECT_EQ(NO_ERROR, ret);
+
+    {
+        Parcel data, reply;
+        ret = target->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY);
+        EXPECT_EQ(0, ret);
+    }
+
+    /* Make sure it's dead */
+    testDeathRecipient->waitEvent(5);
+
+    /* Now, pass the ref to another process and ask that process to
+     * call linkToDeath() on it, and wait for a response. This tests
+     * two things:
+     * 1) You still get death notifications when calling linkToDeath()
+     *    on a ref that is already dead when it was passed to you.
+     * 2) That death notifications are not directly pushed to the thread
+     *    registering them, but to the threadpool (proc workqueue) instead.
+     *
+     * 2) is tested because the thread handling BINDER_LIB_TEST_DEATH_TRANSACTION
+     * is blocked on a condition variable waiting for the death notification to be
+     * called; therefore, that thread is not available for handling proc work.
+     * So, if the death notification was pushed to the thread workqueue, the callback
+     * would never be called, and the test would timeout and fail.
+     *
+     * Note that we can't do this part of the test from this thread itself, because
+     * the binder driver would only push death notifications to the thread if
+     * it is a looper thread, which this thread is not.
+     *
+     * See b/23525545 for details.
+     */
+    {
+        Parcel data, reply;
+
+        callback = new BinderLibTestCallBack();
+        data.writeStrongBinder(target);
+        data.writeStrongBinder(callback);
+        ret = client->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply, TF_ONE_WAY);
+        EXPECT_EQ(NO_ERROR, ret);
+    }
+
+    ret = callback->waitEvent(5);
+    EXPECT_EQ(NO_ERROR, ret);
+    ret = callback->getResult();
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
 TEST_F(BinderLibTest, PassFile) {
     int ret;
     int pipefd[2];
@@ -631,7 +730,7 @@
     }
 
     ret = read(pipefd[0], buf, sizeof(buf));
-    EXPECT_EQ(sizeof(buf), ret);
+    EXPECT_EQ(sizeof(buf), (size_t)ret);
     EXPECT_EQ(write_value, buf[0]);
 
     waitForReadData(pipefd[0], 5000); /* wait for other proccess to close pipe */
@@ -670,6 +769,81 @@
     EXPECT_GE(ret, 0);
 }
 
+TEST_F(BinderLibTest, CheckHandleZeroBinderHighBitsZeroCookie) {
+    status_t ret;
+    Parcel data, reply;
+
+    ret = m_server->transact(BINDER_LIB_TEST_GET_SELF_TRANSACTION, data, &reply);
+    EXPECT_EQ(NO_ERROR, ret);
+
+    const flat_binder_object *fb = reply.readObject(false);
+    ASSERT_TRUE(fb != NULL);
+    EXPECT_EQ(fb->hdr.type, BINDER_TYPE_HANDLE);
+    EXPECT_EQ(ProcessState::self()->getStrongProxyForHandle(fb->handle), m_server);
+    EXPECT_EQ(fb->cookie, (binder_uintptr_t)0);
+    EXPECT_EQ(fb->binder >> 32, (binder_uintptr_t)0);
+}
+
+TEST_F(BinderLibTest, FreedBinder) {
+    status_t ret;
+
+    sp<IBinder> server = addServer();
+    ASSERT_TRUE(server != NULL);
+
+    __u32 freedHandle;
+    wp<IBinder> keepFreedBinder;
+    {
+        Parcel data, reply;
+        data.writeBool(false); /* request weak reference */
+        ret = server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply);
+        ASSERT_EQ(NO_ERROR, ret);
+        struct flat_binder_object *freed = (struct flat_binder_object *)(reply.data());
+        freedHandle = freed->handle;
+        /* Add a weak ref to the freed binder so the driver does not
+         * delete its reference to it - otherwise the transaction
+         * fails regardless of whether the driver is fixed.
+         */
+        keepFreedBinder = reply.readWeakBinder();
+    }
+    {
+        Parcel data, reply;
+        data.writeStrongBinder(server);
+        /* Replace original handle with handle to the freed binder */
+        struct flat_binder_object *strong = (struct flat_binder_object *)(data.data());
+        __u32 oldHandle = strong->handle;
+        strong->handle = freedHandle;
+        ret = server->transact(BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, data, &reply);
+        /* Returns DEAD_OBJECT (-32) if target crashes and
+         * FAILED_TRANSACTION if the driver rejects the invalid
+         * object.
+         */
+        EXPECT_EQ((status_t)FAILED_TRANSACTION, ret);
+        /* Restore original handle so parcel destructor does not use
+         * the wrong handle.
+         */
+        strong->handle = oldHandle;
+    }
+}
+
+TEST_F(BinderLibTest, CheckNoHeaderMappedInUser) {
+    status_t ret;
+    Parcel data, reply;
+    sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack();
+    for (int i = 0; i < 2; i++) {
+        BinderLibTestBundle datai;
+        datai.appendFrom(&data, 0, data.dataSize());
+
+        data.freeData();
+        data.writeInt32(1);
+        data.writeStrongBinder(callBack);
+        data.writeInt32(BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF);
+
+        datai.appendTo(&data);
+    }
+    ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply);
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
 class BinderLibTestService : public BBinder
 {
     public:
@@ -771,6 +945,9 @@
                 binder->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2);
                 return NO_ERROR;
             }
+            case BINDER_LIB_TEST_GET_SELF_TRANSACTION:
+                reply->writeStrongBinder(this);
+                return NO_ERROR;
             case BINDER_LIB_TEST_GET_ID_TRANSACTION:
                 reply->writeInt32(m_id);
                 return NO_ERROR;
@@ -884,6 +1061,16 @@
                 while (wait(NULL) != -1 || errno != ECHILD)
                     ;
                 exit(EXIT_SUCCESS);
+            case BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION: {
+                bool strongRef = data.readBool();
+                sp<IBinder> binder = new BBinder();
+                if (strongRef) {
+                    reply->writeStrongBinder(binder);
+                } else {
+                    reply->writeWeakBinder(binder);
+                }
+                return NO_ERROR;
+            }
             default:
                 return UNKNOWN_TRANSACTION;
             };
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index 71b96d4..455f2c4 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -101,18 +101,21 @@
 };
 
 static const uint32_t num_buckets = 128;
-static const uint64_t max_time_bucket = 50ull * 1000000;
-static const uint64_t time_per_bucket = max_time_bucket / num_buckets;
-static constexpr float time_per_bucket_ms = time_per_bucket / 1.0E6;
+static uint64_t max_time_bucket = 50ull * 1000000;
+static uint64_t time_per_bucket = max_time_bucket / num_buckets;
 
 struct ProcResults {
-    uint64_t m_best = max_time_bucket;
     uint64_t m_worst = 0;
     uint32_t m_buckets[num_buckets] = {0};
     uint64_t m_transactions = 0;
+    uint64_t m_long_transactions = 0;
     uint64_t m_total_time = 0;
+    uint64_t m_best = max_time_bucket;
 
     void add_time(uint64_t time) {
+        if (time > max_time_bucket) {
+            m_long_transactions++;
+        }
         m_buckets[min(time, max_time_bucket-1) / time_per_bucket] += 1;
         m_best = min(time, m_best);
         m_worst = max(time, m_worst);
@@ -127,16 +130,24 @@
         ret.m_worst = max(a.m_worst, b.m_worst);
         ret.m_best = min(a.m_best, b.m_best);
         ret.m_transactions = a.m_transactions + b.m_transactions;
+        ret.m_long_transactions = a.m_long_transactions + b.m_long_transactions;
         ret.m_total_time = a.m_total_time + b.m_total_time;
         return ret;
     }
     void dump() {
+        if (m_long_transactions > 0) {
+            cout << (double)m_long_transactions / m_transactions << "% of transactions took longer "
+                "than estimated max latency. Consider setting -m to be higher than "
+                 << m_worst / 1000 << " microseconds" << endl;
+        }
+
         double best = (double)m_best / 1.0E6;
         double worst = (double)m_worst / 1.0E6;
         double average = (double)m_total_time / m_transactions / 1.0E6;
         cout << "average:" << average << "ms worst:" << worst << "ms best:" << best << "ms" << endl;
 
         uint64_t cur_total = 0;
+        float time_per_bucket_ms = time_per_bucket / 1.0E6;
         for (int i = 0; i < num_buckets; i++) {
             float cur_time = time_per_bucket_ms * i + 0.5f * time_per_bucket_ms;
             if ((cur_total < 0.5f * m_transactions) && (cur_total + m_buckets[i] >= 0.5f * m_transactions)) {
@@ -154,7 +165,6 @@
             cur_total += m_buckets[i];
         }
         cout << endl;
-
     }
 };
 
@@ -166,11 +176,12 @@
     return serviceName;
 }
 
-void worker_fx(
-    int num,
-    int worker_count,
-    int iterations,
-    Pipe p)
+void worker_fx(int num,
+               int worker_count,
+               int iterations,
+               int payload_size,
+               bool cs_pair,
+               Pipe p)
 {
     // Create BinderWorkerService and for go.
     ProcessState::self()->startThreadPool();
@@ -182,22 +193,32 @@
     p.signal();
     p.wait();
 
+    // If client/server pairs, then half the workers are
+    // servers and half are clients
+    int server_count = cs_pair ? worker_count / 2 : worker_count;
+
     // Get references to other binder services.
     cout << "Created BinderWorker" << num << endl;
     (void)worker_count;
     vector<sp<IBinder> > workers;
-    for (int i = 0; i < worker_count; i++) {
+    for (int i = 0; i < server_count; i++) {
         if (num == i)
             continue;
         workers.push_back(serviceMgr->getService(generateServiceName(i)));
     }
 
-    // Run the benchmark.
+    // Run the benchmark if client
     ProcResults results;
     chrono::time_point<chrono::high_resolution_clock> start, end;
-    for (int i = 0; i < iterations; i++) {
-        int target = rand() % workers.size();
+    for (int i = 0; (!cs_pair || num >= server_count) && i < iterations; i++) {
         Parcel data, reply;
+        int target = cs_pair ? num % server_count : rand() % workers.size();
+        int sz = payload_size;
+
+        while (sz > sizeof(uint32_t)) {
+            data.writeInt32(0);
+            sz -= sizeof(uint32_t);
+        }
         start = chrono::high_resolution_clock::now();
         status_t ret = workers[target]->transact(BINDER_NOP, data, &reply);
         end = chrono::high_resolution_clock::now();
@@ -210,6 +231,7 @@
            exit(EXIT_FAILURE);
         }
     }
+
     // Signal completion to master and wait.
     p.signal();
     p.wait();
@@ -221,7 +243,7 @@
     exit(EXIT_SUCCESS);
 }
 
-Pipe make_worker(int num, int iterations, int worker_count)
+Pipe make_worker(int num, int iterations, int worker_count, int payload_size, bool cs_pair)
 {
     auto pipe_pair = Pipe::createPipePair();
     pid_t pid = fork();
@@ -230,7 +252,7 @@
         return move(get<0>(pipe_pair));
     } else {
         /* child */
-        worker_fx(num, worker_count, iterations, move(get<1>(pipe_pair)));
+        worker_fx(num, worker_count, iterations, payload_size, cs_pair, move(get<1>(pipe_pair)));
         /* never get here */
         return move(get<0>(pipe_pair));
     }
@@ -251,35 +273,19 @@
     }
 }
 
-int main(int argc, char *argv[])
+void run_main(int iterations,
+              int workers,
+              int payload_size,
+              int cs_pair,
+              bool training_round=false)
 {
-    int workers = 2;
-    int iterations = 10000;
-    (void)argc;
-    (void)argv;
     vector<Pipe> pipes;
-
-    // Parse arguments.
-    for (int i = 1; i < argc; i++) {
-        if (string(argv[i]) == "-w") {
-            workers = atoi(argv[i+1]);
-            i++;
-            continue;
-        }
-        if (string(argv[i]) == "-i") {
-            iterations = atoi(argv[i+1]);
-            i++;
-            continue;
-        }
-    }
-
     // Create all the workers and wait for them to spawn.
     for (int i = 0; i < workers; i++) {
-        pipes.push_back(make_worker(i, iterations, workers));
+        pipes.push_back(make_worker(i, iterations, workers, payload_size, cs_pair));
     }
     wait_all(pipes);
 
-
     // Run the workers and wait for completion.
     chrono::time_point<chrono::high_resolution_clock> start, end;
     cout << "waiting for workers to complete" << endl;
@@ -301,7 +307,6 @@
         pipes[i].recv(tmp_results);
         tot_results = ProcResults::combine(tot_results, tmp_results);
     }
-    tot_results.dump();
 
     // Kill all the workers.
     cout << "killing workers" << endl;
@@ -313,5 +318,83 @@
             cout << "nonzero child status" << status << endl;
         }
     }
+    if (training_round) {
+        // sets max_time_bucket to 2 * m_worst from the training round.
+        // Also needs to adjust time_per_bucket accordingly.
+        max_time_bucket = 2 * tot_results.m_worst;
+        time_per_bucket = max_time_bucket / num_buckets;
+        cout << "Max latency during training: " << tot_results.m_worst / 1.0E6 << "ms" << endl;
+    } else {
+            tot_results.dump();
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    int workers = 2;
+    int iterations = 10000;
+    int payload_size = 0;
+    bool cs_pair = false;
+    bool training_round = false;
+    (void)argc;
+    (void)argv;
+
+    // Parse arguments.
+    for (int i = 1; i < argc; i++) {
+        if (string(argv[i]) == "--help") {
+            cout << "Usage: binderThroughputTest [OPTIONS]" << endl;
+            cout << "\t-i N    : Specify number of iterations." << endl;
+            cout << "\t-m N    : Specify expected max latency in microseconds." << endl;
+            cout << "\t-p      : Split workers into client/server pairs." << endl;
+            cout << "\t-s N    : Specify payload size." << endl;
+            cout << "\t-t N    : Run training round." << endl;
+            cout << "\t-w N    : Specify total number of workers." << endl;
+            return 0;
+        }
+        if (string(argv[i]) == "-w") {
+            workers = atoi(argv[i+1]);
+            i++;
+            continue;
+        }
+        if (string(argv[i]) == "-i") {
+            iterations = atoi(argv[i+1]);
+            i++;
+            continue;
+        }
+        if (string(argv[i]) == "-s") {
+            payload_size = atoi(argv[i+1]);
+            i++;
+        }
+        if (string(argv[i]) == "-p") {
+            // client/server pairs instead of spreading
+            // requests to all workers. If true, half
+            // the workers become clients and half servers
+            cs_pair = true;
+        }
+        if (string(argv[i]) == "-t") {
+            // Run one training round before actually collecting data
+            // to get an approximation of max latency.
+            training_round = true;
+        }
+        if (string(argv[i]) == "-m") {
+            // Caller specified the max latency in microseconds.
+            // No need to run training round in this case.
+            if (atoi(argv[i+1]) > 0) {
+                max_time_bucket = strtoull(argv[i+1], (char **)NULL, 10) * 1000;
+                i++;
+            } else {
+                cout << "Max latency -m must be positive." << endl;
+                exit(EXIT_FAILURE);
+            }
+        }
+    }
+
+    if (training_round) {
+        cout << "Start training round" << endl;
+        run_main(iterations, workers, payload_size, cs_pair, training_round=true);
+        cout << "Completed training round" << endl << endl;
+    }
+
+    run_main(iterations, workers, payload_size, cs_pair);
     return 0;
 }
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
index fe9e05a..13f03b1 100644
--- a/libs/binder/tests/schd-dbg.cpp
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -40,7 +40,7 @@
 // GOOD_SYNC_MIN is considered as good
 #define GOOD_SYNC_MIN (0.6)
 
-#define DUMP_PRICISION 3
+#define DUMP_PRESICION 2
 
 string trace_path = "/sys/kernel/debug/tracing";
 
@@ -246,10 +246,11 @@
     double worst = (double)m_worst / 1.0E6;
     double average = (double)m_total_time / m_transactions / 1.0E6;
     // FIXME: libjson?
-    cout << std::setprecision(DUMP_PRICISION) << "{ \"avg\":" << setw(5) << left
-         << average << ", \"wst\":" << setw(5) << left << worst
-         << ", \"bst\":" << setw(5) << left << best << ", \"miss\":" << setw(5)
-         << left << m_miss << ", \"meetR\":" << setw(3) << left
+    int W = DUMP_PRESICION + 2;
+    cout << setprecision(DUMP_PRESICION) << "{ \"avg\":" << setw(W) << left
+         << average << ",\"wst\":" << setw(W) << left << worst
+         << ",\"bst\":" << setw(W) << left << best << ",\"miss\":" << left
+         << m_miss << ",\"meetR\":" << left << setprecision(DUMP_PRESICION + 3)
          << (1.0 - (double)m_miss / m_transactions) << "}";
   }
 };
@@ -272,8 +273,15 @@
   }
 }
 
+typedef struct {
+  void* result;
+  int target;
+} thread_priv_t;
+
 static void* thread_start(void* p) {
-  Results* results_fifo = (Results*)p;
+  thread_priv_t* priv = (thread_priv_t*)p;
+  int target = priv->target;
+  Results* results_fifo = (Results*)priv->result;
   Parcel data, reply;
   Tick sta, end;
 
@@ -281,7 +289,7 @@
   thread_dump("fifo-caller");
 
   sta = tickNow();
-  status_t ret = workers[0]->transact(BINDER_NOP, data, &reply);
+  status_t ret = workers[target]->transact(BINDER_NOP, data, &reply);
   end = tickNow();
   results_fifo->add_time(tickNano(sta, end));
 
@@ -291,16 +299,19 @@
 }
 
 // create a fifo thread to transact and wait it to finished
-static void thread_transaction(Results* results_fifo) {
+static void thread_transaction(int target, Results* results_fifo) {
+  thread_priv_t thread_priv;
   void* dummy;
   pthread_t thread;
   pthread_attr_t attr;
   struct sched_param param;
+  thread_priv.target = target;
+  thread_priv.result = results_fifo;
   ASSERT(!pthread_attr_init(&attr));
   ASSERT(!pthread_attr_setschedpolicy(&attr, SCHED_FIFO));
   param.sched_priority = sched_get_priority_max(SCHED_FIFO);
   ASSERT(!pthread_attr_setschedparam(&attr, &param));
-  ASSERT(!pthread_create(&thread, &attr, &thread_start, results_fifo));
+  ASSERT(!pthread_create(&thread, &attr, &thread_start, &thread_priv));
   ASSERT(!pthread_join(thread, &dummy));
 }
 
@@ -316,7 +327,9 @@
   sp<IServiceManager> serviceMgr = defaultServiceManager();
   sp<BinderWorkerService> service = new BinderWorkerService;
   serviceMgr->addService(generateServiceName(num), service);
+  // init done
   p.signal();
+  // wait for kick-off
   p.wait();
 
   // If client/server pairs, then half the workers are
@@ -338,7 +351,7 @@
     int target = num % server_count;
 
     // 1. transaction by fifo thread
-    thread_transaction(&results_fifo);
+    thread_transaction(target, &results_fifo);
     parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
     thread_dump("other-caller");
 
@@ -356,6 +369,7 @@
   p.wait();
 
   p.send(&dummy);
+  // wait for kill
   p.wait();
   // Client for each pair dump here
   if (is_client(num)) {
@@ -367,10 +381,10 @@
          << "\"S\":" << (no_trans - no_sync) << ",\"I\":" << no_trans << ","
          << "\"R\":" << sync_ratio << "," << endl;
 
-    cout << "      \"other_ms\":";
+    cout << "  \"other_ms\":";
     results_other.dump();
     cout << "," << endl;
-    cout << "      \"fifo_ms\": ";
+    cout << "  \"fifo_ms\": ";
     results_fifo.dump();
     cout << endl;
     cout << "}," << endl;
@@ -463,12 +477,17 @@
   for (int i = 0; i < no_process; i++) {
     pipes.push_back(make_process(i, iterations, no_process, payload_size));
   }
+  // wait for init done
   wait_all(pipes);
+  // kick-off iterations
   signal_all(pipes);
+  // wait for completion
   wait_all(pipes);
+  // start to send result
   signal_all(pipes);
   for (int i = 0; i < no_process; i++) {
     int status;
+    // kill
     pipes[i].signal();
     wait(&status);
     // the exit status is number of transactions without priority inheritance