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.
19 import android
.os
.SystemClock
;
21 import java
.util
.concurrent
.TimeoutException
;
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.
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);
49 * public MyMethodCaller(IRemoteInterface target) {
53 * public Object onCallMyMethod(Object arg) throws RemoteException {
54 * final int sequence = onBeforeRemoteCall();
55 * mTarget.myMethod(arg, sequence);
56 * return getResultTimed(sequence);
61 * @param <T> The type of the expected result.
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
;
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
);
98 throw new TimeoutException("No reponse for sequence: " + sequence
);
106 public final void onRemoteMethodResult(T result
, int sequence
) {
107 synchronized (mLock
) {
108 if (sequence
== mAwaitedSequence
) {
109 mReceivedSequence
= sequence
;
116 private boolean waitForResultTimedLocked(int sequence
) {
117 final long startMillis
= SystemClock
.uptimeMillis();
120 if (mReceivedSequence
== sequence
) {
123 final long elapsedMillis
= SystemClock
.uptimeMillis() - startMillis
;
124 final long waitMillis
= mCallTimeoutMillis
- elapsedMillis
;
125 if (waitMillis
<= 0) {
128 mLock
.wait(waitMillis
);
129 } catch (InterruptedException ie
) {