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