1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 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 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, 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. 15 */ 16 17 package com.android.car.internal; 18 19 import android.annotation.Nullable; 20 import android.car.IResultCallback; 21 import android.car.ResultCallback; 22 import android.car.builtin.util.Slogf; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.util.Log; 26 27 import com.android.internal.annotations.GuardedBy; 28 29 import java.util.Objects; 30 import java.util.concurrent.Executor; 31 32 /** 33 * Implements a Parcelable class which takes {@link ResultCallback} as input and provides 34 * {@link #complete(Object)} call to the binder receiver to send result back asynchronously. 35 * 36 * <p> 37 * Managers can create this class with {@link ResultCallback} and {@link Executor} and pass it 38 * across the binder from manager to service. On the service side, when results are available, 39 * {@link #complete(Object)} should be called with the result. 40 * 41 * @param <V> refer to a Parcelable object. 42 * 43 * @hide 44 */ 45 public class ResultCallbackImpl<V> implements Parcelable { 46 47 private static final String TAG = ResultCallbackImpl.class.getSimpleName(); 48 private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG); 49 50 private final Object mLock = new Object(); 51 52 // TODO(b/269040634): Revisit this logic based on the CL discussion 53 @GuardedBy("mLock") 54 @Nullable 55 private IResultCallback mReceiver; 56 57 @Nullable 58 private final ResultCallback<V> mCallback; 59 @Nullable 60 private final Executor mExecutor; 61 ResultCallbackImpl(Executor executor, ResultCallback<V> callback)62 public ResultCallbackImpl(Executor executor, ResultCallback<V> callback) { 63 mExecutor = Objects.requireNonNull(executor, "executor cannot be null"); 64 mCallback = Objects.requireNonNull(callback, "callback cannot be null"); 65 } 66 ResultCallbackImpl(Parcel in)67 ResultCallbackImpl(Parcel in) { 68 mExecutor = null; 69 mCallback = null; 70 mReceiver = IResultCallback.Stub.asInterface(in.readStrongBinder()); 71 } 72 73 /** 74 * Calls to update the {code result}. 75 */ complete(V result)76 public void complete(V result) { 77 try { 78 IResultCallback receiver; 79 synchronized (mLock) { 80 receiver = mReceiver; 81 } 82 83 if (receiver == null) { 84 // Receive could be null if the call is not IPC. 85 sendResult(result); 86 return; 87 } 88 ResultWrapper<V> wrapper = new ResultWrapper<V>(result); 89 receiver.complete(wrapper); 90 } catch (Exception e) { 91 Slogf.w(TAG, e, "ResultCallbackImpl failed."); 92 } 93 } 94 95 /** 96 * Called before sending the sending the result to the callback. 97 */ onCompleted(V result)98 protected void onCompleted(V result) {} 99 sendResult(V result)100 private void sendResult(V result) { 101 if (mExecutor == null || mCallback == null) { 102 // This should never happen. sendResult call will always be executed on the sender side. 103 Slogf.wtf(TAG, "Executor or callback can not be null. Executor:%s Callback:%s", 104 mExecutor, mCallback); 105 return; 106 } 107 108 if (DBG) { 109 Slogf.d(TAG, "Sending results - %s", result.toString()); 110 } 111 112 onCompleted(result); 113 mExecutor.execute(() -> mCallback.onResult(result)); 114 } 115 116 @Override describeContents()117 public int describeContents() { 118 return 0; 119 } 120 121 @Override writeToParcel(Parcel dest, int flags)122 public void writeToParcel(Parcel dest, int flags) { 123 synchronized (mLock) { 124 if (mReceiver == null) { 125 mReceiver = new MyCallbackReceiver(); 126 } 127 dest.writeStrongBinder(mReceiver.asBinder()); 128 } 129 } 130 131 private final class MyCallbackReceiver extends IResultCallback.Stub { 132 @Override complete(ResultWrapper resultCallback)133 public void complete(ResultWrapper resultCallback) { 134 sendResult((V) resultCallback.getResult()); 135 } 136 } 137 138 public static final Parcelable.Creator<ResultCallbackImpl> CREATOR = 139 new Parcelable.Creator<ResultCallbackImpl>() { 140 public ResultCallbackImpl createFromParcel(Parcel in) { 141 return new ResultCallbackImpl(in); 142 } 143 144 public ResultCallbackImpl[] newArray(int size) { 145 return new ResultCallbackImpl[size]; 146 } 147 }; 148 } 149