14b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/* 24b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Copyright (C) 2013 The Android Open Source Project 34b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * 44b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License"); 54b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * you may not use this file except in compliance with the License. 64b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * You may obtain a copy of the License at 74b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * 84b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * http://www.apache.org/licenses/LICENSE-2.0 94b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * 104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Unless required by applicable law or agreed to in writing, software 114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS, 124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * See the License for the specific language governing permissions and 144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * limitations under the License. 154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */ 164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpackage android.util; 184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.SystemClock; 20a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmannimport com.android.internal.annotations.GuardedBy; 214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 224b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.concurrent.TimeoutException; 234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/** 254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * This is a helper class for making an async one way call and 264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * its async one way response response in a sync fashion within 274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * a timeout. The key idea is to call the remote method with a 284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * sequence number and a callback and then starting to wait for 294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * the response. The remote method calls back with the result and 304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * the sequence number. If the response comes within the timeout 314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * and its sequence number is the one sent in the method invocation, 324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * then the call succeeded. If the response does not come within 33a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * the timeout then the call failed. 344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p> 354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Typical usage is: 364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p> 374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p><pre><code> 384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * public class MyMethodCaller extends TimeoutRemoteCallHelper<Object> { 394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * // The one way remote method to call. 404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * private final IRemoteInterface mTarget; 414b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * 424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * // One way callback invoked when the remote method is done. 434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * private final IRemoteCallback mCallback = new IRemoteCallback.Stub() { 444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * public void onCompleted(Object result, int sequence) { 454b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * onRemoteMethodResult(result, sequence); 464b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * } 474b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * }; 484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * 494b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * public MyMethodCaller(IRemoteInterface target) { 504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * mTarget = target; 514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * } 524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * 534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * public Object onCallMyMethod(Object arg) throws RemoteException { 544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * final int sequence = onBeforeRemoteCall(); 554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * mTarget.myMethod(arg, sequence); 564b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * return getResultTimed(sequence); 574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * } 584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * } 594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </code></pre></p> 604b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * 614b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * @param <T> The type of the expected result. 624b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * 634b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * @hide 644b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */ 654b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpublic abstract class TimedRemoteCaller<T> { 664b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 674b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov public static final long DEFAULT_CALL_TIMEOUT_MILLIS = 5000; 684b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 694b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov private final Object mLock = new Object(); 704b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 714b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov private final long mCallTimeoutMillis; 724b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 73a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann /** The callbacks we are waiting for, key == sequence id, value == 1 */ 74a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann @GuardedBy("mLock") 75a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann private final SparseIntArray mAwaitedCalls = new SparseIntArray(1); 764b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 77a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann /** The callbacks we received but for which the result has not yet been reported */ 78a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann @GuardedBy("mLock") 79a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann private final SparseArray<T> mReceivedCalls = new SparseArray<>(1); 804b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 81a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann @GuardedBy("mLock") 82a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann private int mSequenceCounter; 834b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 84a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann /** 85a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * Create a new timed caller. 86a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * 87a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * @param callTimeoutMillis The time to wait in {@link #getResultTimed} before a timed call will 88a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * be declared timed out 89a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann */ 904b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov public TimedRemoteCaller(long callTimeoutMillis) { 914b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov mCallTimeoutMillis = callTimeoutMillis; 924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 934b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 94a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann /** 95a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * Indicate that a timed call will be made. 96a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * 97a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * @return The sequence id for the call 98a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann */ 99a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann protected final int onBeforeRemoteCall() { 1004b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov synchronized (mLock) { 101a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann int sequenceId; 102a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann do { 103a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann sequenceId = mSequenceCounter++; 104a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann } while (mAwaitedCalls.get(sequenceId) != 0); 1054b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 106a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann mAwaitedCalls.put(sequenceId, 1); 107a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann 108a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann return sequenceId; 1094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 1104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 1114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 112a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann /** 113a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * Indicate that the timed call has returned. 114a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * 115a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * @param result The result of the timed call 116a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * @param sequence The sequence id of the call (from {@link #onBeforeRemoteCall()}) 117a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann */ 118a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann protected final void onRemoteMethodResult(T result, int sequence) { 1194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov synchronized (mLock) { 120a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann // Do nothing if we do not await the call anymore as it must have timed out 121a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann boolean containedSequenceId = mAwaitedCalls.get(sequence) != 0; 122a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann if (containedSequenceId) { 123a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann mAwaitedCalls.delete(sequence); 124a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann mReceivedCalls.put(sequence, result); 1254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov mLock.notifyAll(); 1264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 1274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 1284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 1294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 130a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann /** 131a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * Wait until the timed call has returned. 132a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * 133a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * @param sequence The sequence id of the call (from {@link #onBeforeRemoteCall()}) 134a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * 135a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann * @return The result of the timed call (set in {@link #onRemoteMethodResult(Object, int)}) 136a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann */ 137a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann protected final T getResultTimed(int sequence) throws TimeoutException { 1384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov final long startMillis = SystemClock.uptimeMillis(); 1394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov while (true) { 1404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov try { 141a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann synchronized (mLock) { 142a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann if (mReceivedCalls.indexOfKey(sequence) >= 0) { 143a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann return mReceivedCalls.removeReturnOld(sequence); 144a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann } 145a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; 146a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann final long waitMillis = mCallTimeoutMillis - elapsedMillis; 147a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann if (waitMillis <= 0) { 148a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann mAwaitedCalls.delete(sequence); 149a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann throw new TimeoutException("No response for sequence: " + sequence); 150a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann } 151a01bda837b6c50bf051b229051d1d2d4cde5ed68Philip P. Moltmann mLock.wait(waitMillis); 1524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 1534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } catch (InterruptedException ie) { 1544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov /* ignore */ 1554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 1564b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 1574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 1584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov} 159