Move to Android N-MR1 SDK.
[android_tools.git] / sdk / sources / android-25 / android / util / TimedRemoteCaller.java
blobabb2b6401d7173a3f6bf1270efe8c06d275c1d75
1 /*
2 * Copyright (C) 2013 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package android.util;
19 import android.os.SystemClock;
21 import java.util.concurrent.TimeoutException;
23 /**
24 * This is a helper class for making an async one way call and
25 * its async one way response response in a sync fashion within
26 * a timeout. The key idea is to call the remote method with a
27 * sequence number and a callback and then starting to wait for
28 * the response. The remote method calls back with the result and
29 * the sequence number. If the response comes within the timeout
30 * and its sequence number is the one sent in the method invocation,
31 * then the call succeeded. If the response does not come within
32 * the timeout then the call failed. Older result received when
33 * waiting for the result are ignored.
34 * <p>
35 * Typical usage is:
36 * </p>
37 * <p><pre><code>
38 * public class MyMethodCaller extends TimeoutRemoteCallHelper<Object> {
39 * // The one way remote method to call.
40 * private final IRemoteInterface mTarget;
42 * // One way callback invoked when the remote method is done.
43 * private final IRemoteCallback mCallback = new IRemoteCallback.Stub() {
44 * public void onCompleted(Object result, int sequence) {
45 * onRemoteMethodResult(result, sequence);
46 * }
47 * };
49 * public MyMethodCaller(IRemoteInterface target) {
50 * mTarget = target;
51 * }
53 * public Object onCallMyMethod(Object arg) throws RemoteException {
54 * final int sequence = onBeforeRemoteCall();
55 * mTarget.myMethod(arg, sequence);
56 * return getResultTimed(sequence);
57 * }
58 * }
59 * </code></pre></p>
61 * @param <T> The type of the expected result.
63 * @hide
65 public abstract class TimedRemoteCaller<T> {
67 public static final long DEFAULT_CALL_TIMEOUT_MILLIS = 5000;
69 private static final int UNDEFINED_SEQUENCE = -1;
71 private final Object mLock = new Object();
73 private final long mCallTimeoutMillis;
75 private int mSequenceCounter;
77 private int mReceivedSequence = UNDEFINED_SEQUENCE;
79 private int mAwaitedSequence = UNDEFINED_SEQUENCE;
81 private T mResult;
83 public TimedRemoteCaller(long callTimeoutMillis) {
84 mCallTimeoutMillis = callTimeoutMillis;
87 public final int onBeforeRemoteCall() {
88 synchronized (mLock) {
89 mAwaitedSequence = mSequenceCounter++;
90 return mAwaitedSequence;
94 public final T getResultTimed(int sequence) throws TimeoutException {
95 synchronized (mLock) {
96 final boolean success = waitForResultTimedLocked(sequence);
97 if (!success) {
98 throw new TimeoutException("No reponse for sequence: " + sequence);
100 T result = mResult;
101 mResult = null;
102 return result;
106 public final void onRemoteMethodResult(T result, int sequence) {
107 synchronized (mLock) {
108 if (sequence == mAwaitedSequence) {
109 mReceivedSequence = sequence;
110 mResult = result;
111 mLock.notifyAll();
116 private boolean waitForResultTimedLocked(int sequence) {
117 final long startMillis = SystemClock.uptimeMillis();
118 while (true) {
119 try {
120 if (mReceivedSequence == sequence) {
121 return true;
123 final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
124 final long waitMillis = mCallTimeoutMillis - elapsedMillis;
125 if (waitMillis <= 0) {
126 return false;
128 mLock.wait(waitMillis);
129 } catch (InterruptedException ie) {
130 /* ignore */