Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * 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, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package com.android.frameworks.perftests.am.util;
     18 
     19 import android.os.Bundle;
     20 import android.os.RemoteException;
     21 import android.util.Log;
     22 
     23 import java.util.concurrent.BlockingQueue;
     24 import java.util.concurrent.LinkedBlockingQueue;
     25 import java.util.concurrent.TimeUnit;
     26 
     27 
     28 /**
     29  * TimeReceiver will listen for any messages containing a timestamp by starting a BroadcastReceiver
     30  * which listens for Intents with the SendTime.ACTION_SEND_TIME action.
     31  */
     32 public class TimeReceiver {
     33     private static final String TAG = TimeReceiver.class.getSimpleName();
     34     private static final long DEFAULT_RECEIVE_TIME_TIMEOUT_MILLIS = 10000L;
     35 
     36     private BlockingQueue<ReceivedMessage> mQueue = new LinkedBlockingQueue<>();
     37 
     38     private static class ReceivedMessage {
     39         private final String mReceivedMessageType;
     40         private final long mReceivedTimeNs;
     41 
     42         public ReceivedMessage(String receivedMessageType, long receivedTimeNs) {
     43             mReceivedMessageType = receivedMessageType;
     44             mReceivedTimeNs = receivedTimeNs;
     45         }
     46     }
     47 
     48     public void addTimeForTypeToQueue(String type, long timeNs) {
     49         if (type == null) {
     50             throw new IllegalArgumentException("type is null when adding time to queue");
     51         }
     52         if (timeNs < 0) {
     53             throw new RuntimeException(
     54                     "time is negative/non-existant (" + timeNs + ") when adding time to queue");
     55         }
     56         mQueue.add(new ReceivedMessage(type, timeNs));
     57     }
     58 
     59     public Bundle createReceiveTimeExtraBinder() {
     60         Bundle extras = new Bundle();
     61         extras.putBinder(Constants.EXTRA_RECEIVER_CALLBACK, new ITimeReceiverCallback.Stub() {
     62             @Override
     63             public void sendTime(String type, long timeNs) throws RemoteException {
     64                 addTimeForTypeToQueue(type, timeNs);
     65             }
     66         });
     67         return extras;
     68     }
     69 
     70     public long getReceivedTimeNs(String type) {
     71         return getReceivedTimeNs(type, DEFAULT_RECEIVE_TIME_TIMEOUT_MILLIS);
     72     }
     73 
     74     /**
     75      * Returns a received timestamp with the given type tag. Will throw away any messages with a
     76      * different type tag. If it times out, a RuntimeException is thrown.
     77      */
     78     public long getReceivedTimeNs(String type, long timeoutMs) {
     79         ReceivedMessage message;
     80         long endTimeNs = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs);
     81         do {
     82             long curTimeNs = System.nanoTime();
     83             if (curTimeNs > endTimeNs) {
     84                 throw new RuntimeException("Timed out when listening for a time: " + type);
     85             }
     86             try {
     87                 Log.i(TAG, "waiting for message " + type);
     88                 message = mQueue.poll(endTimeNs - curTimeNs, TimeUnit.NANOSECONDS);
     89             } catch (InterruptedException e) {
     90                 throw new RuntimeException(e);
     91             }
     92             if (message == null) {
     93                 throw new RuntimeException("Timed out when listening for a time: " + type);
     94             }
     95             Log.i(TAG, "got message " + message.mReceivedMessageType);
     96             if (!type.equals(message.mReceivedMessageType)) {
     97                 Log.i(TAG, String.format("Expected type \"%s\", got \"%s\" (%d), skipping", type,
     98                         message.mReceivedMessageType, message.mReceivedTimeNs));
     99             }
    100         } while (!type.equals(message.mReceivedMessageType));
    101         return message.mReceivedTimeNs;
    102     }
    103 
    104     /**
    105      * Clears the message queue.
    106      */
    107     public void clear() {
    108         mQueue.clear();
    109     }
    110 }
    111