1 /*
2  * Copyright (C) 2024 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 android.app.ondeviceintelligence;
18 
19 import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
20 
21 import android.Manifest;
22 import android.annotation.CallbackExecutor;
23 import android.annotation.FlaggedApi;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.RequiresPermission;
27 import android.annotation.SystemApi;
28 import android.annotation.SystemService;
29 import android.content.Context;
30 import android.graphics.Bitmap;
31 import android.os.Binder;
32 import android.os.Bundle;
33 import android.os.CancellationSignal;
34 import android.os.IBinder;
35 import android.os.ICancellationSignal;
36 import android.os.OutcomeReceiver;
37 import android.os.PersistableBundle;
38 import android.os.RemoteCallback;
39 import android.os.RemoteException;
40 import android.system.OsConstants;
41 import android.util.Log;
42 
43 import androidx.annotation.IntDef;
44 
45 import com.android.internal.infra.AndroidFuture;
46 
47 import java.lang.annotation.ElementType;
48 import java.lang.annotation.Retention;
49 import java.lang.annotation.RetentionPolicy;
50 import java.lang.annotation.Target;
51 import java.util.List;
52 import java.util.concurrent.Executor;
53 import java.util.function.LongConsumer;
54 
55 /**
56  * Allows granted apps to manage on-device intelligence service configured on the device. Typical
57  * calling pattern will be to query and setup a required feature before proceeding to request
58  * processing.
59  *
60  * The contracts in this Manager class are designed to be open-ended in general, to allow
61  * interoperability. Therefore, it is recommended that implementations of this system-service
62  * expose this API to the clients via a separate sdk or library which has more defined contract.
63  *
64  * @hide
65  */
66 @SystemApi
67 @SystemService(Context.ON_DEVICE_INTELLIGENCE_SERVICE)
68 @FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE)
69 public final class OnDeviceIntelligenceManager {
70     /**
71      * @hide
72      */
73     public static final String API_VERSION_BUNDLE_KEY = "ApiVersionBundleKey";
74 
75     /**
76      * @hide
77      */
78     public static final String AUGMENT_REQUEST_CONTENT_BUNDLE_KEY =
79             "AugmentRequestContentBundleKey";
80 
81     private static final String TAG = "OnDeviceIntelligence";
82     private final Context mContext;
83     private final IOnDeviceIntelligenceManager mService;
84 
85     /**
86      * @hide
87      */
OnDeviceIntelligenceManager(Context context, IOnDeviceIntelligenceManager service)88     public OnDeviceIntelligenceManager(Context context, IOnDeviceIntelligenceManager service) {
89         mContext = context;
90         mService = service;
91     }
92 
93     /**
94      * Asynchronously get the version of the underlying remote implementation.
95      *
96      * @param versionConsumer  consumer to populate the version of remote implementation.
97      * @param callbackExecutor executor to run the callback on.
98      */
99     @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
getVersion( @onNull @allbackExecutor Executor callbackExecutor, @NonNull LongConsumer versionConsumer)100     public void getVersion(
101             @NonNull @CallbackExecutor Executor callbackExecutor,
102             @NonNull LongConsumer versionConsumer) {
103         try {
104             RemoteCallback callback = new RemoteCallback(result -> {
105                 if (result == null) {
106                     Binder.withCleanCallingIdentity(
107                             () -> callbackExecutor.execute(() -> versionConsumer.accept(0)));
108                 }
109                 long version = result.getLong(API_VERSION_BUNDLE_KEY);
110                 Binder.withCleanCallingIdentity(
111                         () -> callbackExecutor.execute(() -> versionConsumer.accept(version)));
112             });
113             mService.getVersion(callback);
114         } catch (RemoteException e) {
115             throw e.rethrowFromSystemServer();
116         }
117     }
118 
119 
120     /**
121      * Get package name configured for providing the remote implementation for this system service.
122      */
123     @Nullable
124     @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
getRemoteServicePackageName()125     public String getRemoteServicePackageName() {
126         String result;
127         try {
128             result = mService.getRemoteServicePackageName();
129         } catch (RemoteException e) {
130             throw e.rethrowFromSystemServer();
131         }
132         return result;
133     }
134 
135     /**
136      * Asynchronously get feature for a given id.
137      *
138      * @param featureId        the identifier pointing to the feature.
139      * @param featureReceiver  callback to populate the feature object for given identifier.
140      * @param callbackExecutor executor to run the callback on.
141      */
142     @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
getFeature( int featureId, @NonNull @CallbackExecutor Executor callbackExecutor, @NonNull OutcomeReceiver<Feature, OnDeviceIntelligenceException> featureReceiver)143     public void getFeature(
144             int featureId,
145             @NonNull @CallbackExecutor Executor callbackExecutor,
146             @NonNull OutcomeReceiver<Feature, OnDeviceIntelligenceException> featureReceiver) {
147         try {
148             IFeatureCallback callback =
149                     new IFeatureCallback.Stub() {
150                         @Override
151                         public void onSuccess(Feature result) {
152                             Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
153                                     () -> featureReceiver.onResult(result)));
154                         }
155 
156                         @Override
157                         public void onFailure(int errorCode, String errorMessage,
158                                 PersistableBundle errorParams) {
159                             Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
160                                     () -> featureReceiver.onError(
161                                             new OnDeviceIntelligenceException(
162                                                     errorCode, errorMessage, errorParams))));
163                         }
164                     };
165             mService.getFeature(featureId, callback);
166         } catch (RemoteException e) {
167             throw e.rethrowFromSystemServer();
168         }
169     }
170 
171     /**
172      * Asynchronously get a list of features that are supported for the caller.
173      *
174      * @param featureListReceiver callback to populate the list of features.
175      * @param callbackExecutor    executor to run the callback on.
176      */
177     @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
listFeatures( @onNull @allbackExecutor Executor callbackExecutor, @NonNull OutcomeReceiver<List<Feature>, OnDeviceIntelligenceException> featureListReceiver)178     public void listFeatures(
179             @NonNull @CallbackExecutor Executor callbackExecutor,
180             @NonNull OutcomeReceiver<List<Feature>, OnDeviceIntelligenceException> featureListReceiver) {
181         try {
182             IListFeaturesCallback callback =
183                     new IListFeaturesCallback.Stub() {
184                         @Override
185                         public void onSuccess(List<Feature> result) {
186                             Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
187                                     () -> featureListReceiver.onResult(result)));
188                         }
189 
190                         @Override
191                         public void onFailure(int errorCode, String errorMessage,
192                                 PersistableBundle errorParams) {
193                             Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
194                                     () -> featureListReceiver.onError(
195                                             new OnDeviceIntelligenceException(
196                                                     errorCode, errorMessage, errorParams))));
197                         }
198                     };
199             mService.listFeatures(callback);
200         } catch (RemoteException e) {
201             throw e.rethrowFromSystemServer();
202         }
203     }
204 
205     /**
206      * This method should be used to fetch details about a feature which need some additional
207      * computation, that can be inefficient to return in all calls to {@link #getFeature}. Callers
208      * and implementation can utilize the {@link Feature#getFeatureParams()} to pass hint on what
209      * details are expected by the caller.
210      *
211      * @param feature                the feature to check status for.
212      * @param featureDetailsReceiver callback to populate the feature details to.
213      * @param callbackExecutor       executor to run the callback on.
214      */
215     @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
getFeatureDetails(@onNull Feature feature, @NonNull @CallbackExecutor Executor callbackExecutor, @NonNull OutcomeReceiver<FeatureDetails, OnDeviceIntelligenceException> featureDetailsReceiver)216     public void getFeatureDetails(@NonNull Feature feature,
217             @NonNull @CallbackExecutor Executor callbackExecutor,
218             @NonNull OutcomeReceiver<FeatureDetails, OnDeviceIntelligenceException> featureDetailsReceiver) {
219         try {
220             IFeatureDetailsCallback callback = new IFeatureDetailsCallback.Stub() {
221 
222                 @Override
223                 public void onSuccess(FeatureDetails result) {
224                     Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
225                             () -> featureDetailsReceiver.onResult(result)));
226                 }
227 
228                 @Override
229                 public void onFailure(int errorCode, String errorMessage,
230                         PersistableBundle errorParams) {
231                     Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
232                             () -> featureDetailsReceiver.onError(
233                                     new OnDeviceIntelligenceException(errorCode,
234                                             errorMessage, errorParams))));
235                 }
236             };
237             mService.getFeatureDetails(feature, callback);
238         } catch (RemoteException e) {
239             throw e.rethrowFromSystemServer();
240         }
241     }
242 
243     /**
244      * This method handles downloading all model and config files required to process requests
245      * sent against a given feature. The caller can listen to updates on the download status via
246      * the callback.
247      *
248      * Note: If a feature was already requested for downloaded previously, the onDownloadFailed
249      * callback would be invoked with {@link DownloadCallback#DOWNLOAD_FAILURE_STATUS_DOWNLOADING}.
250      * In such cases, clients should query the feature status via {@link #getFeatureDetails} to
251      * check on the feature's download status.
252      *
253      * @param feature            feature to request download for.
254      * @param callback           callback to populate updates about download status.
255      * @param cancellationSignal signal to invoke cancellation on the operation in the remote
256      *                           implementation.
257      * @param callbackExecutor   executor to run the callback on.
258      */
259     @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
requestFeatureDownload(@onNull Feature feature, @Nullable CancellationSignal cancellationSignal, @NonNull @CallbackExecutor Executor callbackExecutor, @NonNull DownloadCallback callback)260     public void requestFeatureDownload(@NonNull Feature feature,
261             @Nullable CancellationSignal cancellationSignal,
262             @NonNull @CallbackExecutor Executor callbackExecutor,
263             @NonNull DownloadCallback callback) {
264         try {
265             IDownloadCallback downloadCallback = new IDownloadCallback.Stub() {
266 
267                 @Override
268                 public void onDownloadStarted(long bytesToDownload) {
269                     Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
270                             () -> callback.onDownloadStarted(bytesToDownload)));
271                 }
272 
273                 @Override
274                 public void onDownloadProgress(long bytesDownloaded) {
275                     Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
276                             () -> callback.onDownloadProgress(bytesDownloaded)));
277                 }
278 
279                 @Override
280                 public void onDownloadFailed(int failureStatus, String errorMessage,
281                         PersistableBundle errorParams) {
282                     Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
283                             () -> callback.onDownloadFailed(failureStatus, errorMessage,
284                                     errorParams)));
285                 }
286 
287                 @Override
288                 public void onDownloadCompleted(PersistableBundle downloadParams) {
289                     Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
290                             () -> callback.onDownloadCompleted(downloadParams)));
291                 }
292             };
293 
294             mService.requestFeatureDownload(feature,
295                     configureRemoteCancellationFuture(cancellationSignal, callbackExecutor),
296                     downloadCallback);
297         } catch (RemoteException e) {
298             throw e.rethrowFromSystemServer();
299         }
300     }
301 
302 
303     /**
304      * The methods computes the token related information for a given request payload using the
305      * provided {@link Feature}.
306      *
307      * @param feature            feature associated with the request.
308      * @param request            request and associated params represented by the Bundle
309      *                           data.
310      * @param outcomeReceiver    callback to populate the token info or exception in case of
311      *                           failure.
312      * @param cancellationSignal signal to invoke cancellation on the operation in the remote
313      *                           implementation.
314      * @param callbackExecutor   executor to run the callback on.
315      */
316     @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
requestTokenInfo(@onNull Feature feature, @NonNull @InferenceParams Bundle request, @Nullable CancellationSignal cancellationSignal, @NonNull @CallbackExecutor Executor callbackExecutor, @NonNull OutcomeReceiver<TokenInfo, OnDeviceIntelligenceException> outcomeReceiver)317     public void requestTokenInfo(@NonNull Feature feature, @NonNull @InferenceParams Bundle request,
318             @Nullable CancellationSignal cancellationSignal,
319             @NonNull @CallbackExecutor Executor callbackExecutor,
320             @NonNull OutcomeReceiver<TokenInfo,
321                     OnDeviceIntelligenceException> outcomeReceiver) {
322         try {
323             ITokenInfoCallback callback = new ITokenInfoCallback.Stub() {
324                 @Override
325                 public void onSuccess(TokenInfo tokenInfo) {
326                     Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
327                             () -> outcomeReceiver.onResult(tokenInfo)));
328                 }
329 
330                 @Override
331                 public void onFailure(int errorCode, String errorMessage,
332                         PersistableBundle errorParams) {
333                     Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
334                             () -> outcomeReceiver.onError(
335                                     new OnDeviceIntelligenceException(
336                                             errorCode, errorMessage, errorParams))));
337                 }
338             };
339 
340             mService.requestTokenInfo(feature, request,
341                     configureRemoteCancellationFuture(cancellationSignal, callbackExecutor),
342                     callback);
343         } catch (RemoteException e) {
344             throw e.rethrowFromSystemServer();
345         }
346     }
347 
348 
349     /**
350      * Asynchronously Process a request based on the associated params, to populate a
351      * response in
352      * {@link OutcomeReceiver#onResult} callback or failure callback status code if there
353      * was a
354      * failure.
355      *
356      * @param feature            feature associated with the request.
357      * @param request            request and associated params represented by the Bundle
358      *                           data.
359      * @param requestType        type of request being sent for processing the content.
360      * @param cancellationSignal signal to invoke cancellation.
361      * @param processingSignal   signal to send custom signals in the
362      *                           remote implementation.
363      * @param callbackExecutor   executor to run the callback on.
364      * @param processingCallback callback to populate the response content and
365      *                           associated params.
366      */
367     @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
processRequest(@onNull Feature feature, @NonNull @InferenceParams Bundle request, @RequestType int requestType, @Nullable CancellationSignal cancellationSignal, @Nullable ProcessingSignal processingSignal, @NonNull @CallbackExecutor Executor callbackExecutor, @NonNull ProcessingCallback processingCallback)368     public void processRequest(@NonNull Feature feature, @NonNull @InferenceParams Bundle request,
369             @RequestType int requestType,
370             @Nullable CancellationSignal cancellationSignal,
371             @Nullable ProcessingSignal processingSignal,
372             @NonNull @CallbackExecutor Executor callbackExecutor,
373             @NonNull ProcessingCallback processingCallback) {
374         try {
375             IResponseCallback callback = new IResponseCallback.Stub() {
376                 @Override
377                 public void onSuccess(@InferenceParams Bundle result) {
378                     Binder.withCleanCallingIdentity(() -> {
379                         callbackExecutor.execute(() -> processingCallback.onResult(result));
380                     });
381                 }
382 
383                 @Override
384                 public void onFailure(int errorCode, String errorMessage,
385                         PersistableBundle errorParams) {
386                     Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
387                             () -> processingCallback.onError(
388                                     new OnDeviceIntelligenceException(
389                                             errorCode, errorMessage, errorParams))));
390                 }
391 
392                 @Override
393                 public void onDataAugmentRequest(@NonNull @InferenceParams Bundle request,
394                         @NonNull RemoteCallback contentCallback) {
395                     Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
396                             () -> processingCallback.onDataAugmentRequest(request, result -> {
397                                 Bundle bundle = new Bundle();
398                                 bundle.putParcelable(AUGMENT_REQUEST_CONTENT_BUNDLE_KEY, result);
399                                 callbackExecutor.execute(() -> contentCallback.sendResult(bundle));
400                             })));
401                 }
402             };
403 
404 
405             mService.processRequest(feature, request, requestType,
406                     configureRemoteCancellationFuture(cancellationSignal, callbackExecutor),
407                     configureRemoteProcessingSignalFuture(processingSignal, callbackExecutor),
408                     callback);
409 
410         } catch (RemoteException e) {
411             throw e.rethrowFromSystemServer();
412         }
413     }
414 
415     /**
416      * Variation of {@link #processRequest} that asynchronously processes a request in a
417      * streaming
418      * fashion, where new content is pushed to caller in chunks via the
419      * {@link StreamingProcessingCallback#onPartialResult}. After the streaming is complete,
420      * the service should call {@link StreamingProcessingCallback#onResult} and can optionally
421      * populate the complete the full response {@link Bundle} as part of the callback in cases
422      * when the final response contains an enhanced aggregation of the contents already
423      * streamed.
424      *
425      * @param feature                     feature associated with the request.
426      * @param request                     request and associated params represented by the Bundle
427      *                                    data.
428      * @param requestType                 type of request being sent for processing the content.
429      * @param cancellationSignal          signal to invoke cancellation.
430      * @param processingSignal            signal to send custom signals in the
431      *                                    remote implementation.
432      * @param streamingProcessingCallback streaming callback to populate the response content and
433      *                                    associated params.
434      * @param callbackExecutor            executor to run the callback on.
435      */
436     @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
processRequestStreaming(@onNull Feature feature, @NonNull @InferenceParams Bundle request, @RequestType int requestType, @Nullable CancellationSignal cancellationSignal, @Nullable ProcessingSignal processingSignal, @NonNull @CallbackExecutor Executor callbackExecutor, @NonNull StreamingProcessingCallback streamingProcessingCallback)437     public void processRequestStreaming(@NonNull Feature feature,
438             @NonNull @InferenceParams Bundle request,
439             @RequestType int requestType,
440             @Nullable CancellationSignal cancellationSignal,
441             @Nullable ProcessingSignal processingSignal,
442             @NonNull @CallbackExecutor Executor callbackExecutor,
443             @NonNull StreamingProcessingCallback streamingProcessingCallback) {
444         try {
445             IStreamingResponseCallback callback = new IStreamingResponseCallback.Stub() {
446                 @Override
447                 public void onNewContent(@InferenceParams Bundle result) {
448                     Binder.withCleanCallingIdentity(() -> {
449                         callbackExecutor.execute(
450                                 () -> streamingProcessingCallback.onPartialResult(result));
451                     });
452                 }
453 
454                 @Override
455                 public void onSuccess(@InferenceParams Bundle result) {
456                     Binder.withCleanCallingIdentity(() -> {
457                         callbackExecutor.execute(
458                                 () -> streamingProcessingCallback.onResult(result));
459                     });
460                 }
461 
462                 @Override
463                 public void onFailure(int errorCode, String errorMessage,
464                         PersistableBundle errorParams) {
465                     Binder.withCleanCallingIdentity(() -> {
466                         callbackExecutor.execute(
467                                 () -> streamingProcessingCallback.onError(
468                                         new OnDeviceIntelligenceException(
469                                                 errorCode, errorMessage, errorParams)));
470                     });
471                 }
472 
473 
474                 @Override
475                 public void onDataAugmentRequest(@NonNull @InferenceParams Bundle content,
476                         @NonNull RemoteCallback contentCallback) {
477                     Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
478                             () -> streamingProcessingCallback.onDataAugmentRequest(content,
479                                     contentResponse -> {
480                                         Bundle bundle = new Bundle();
481                                         bundle.putParcelable(AUGMENT_REQUEST_CONTENT_BUNDLE_KEY,
482                                                 contentResponse);
483                                         callbackExecutor.execute(
484                                                 () -> contentCallback.sendResult(bundle));
485                                     })));
486                 }
487             };
488 
489             mService.processRequestStreaming(
490                     feature, request, requestType,
491                     configureRemoteCancellationFuture(cancellationSignal, callbackExecutor),
492                     configureRemoteProcessingSignalFuture(processingSignal, callbackExecutor),
493                     callback);
494         } catch (RemoteException e) {
495             throw e.rethrowFromSystemServer();
496         }
497     }
498 
499     /**
500      * This is primarily intended to be used to attribute/blame on-device intelligence power usage,
501      * via the configured remote implementation, to its actual caller.
502      *
503      * @param startTimeEpochMillis epoch millis used to filter the InferenceInfo events.
504      * @return InferenceInfo events since the passed in startTimeEpochMillis.
505      *
506      * @hide
507      */
508     @RequiresPermission(Manifest.permission.DUMP)
getLatestInferenceInfo(long startTimeEpochMillis)509     public List<InferenceInfo> getLatestInferenceInfo(long startTimeEpochMillis) {
510         try {
511             return mService.getLatestInferenceInfo(startTimeEpochMillis);
512         } catch (RemoteException e) {
513             throw e.rethrowFromSystemServer();
514         }
515     }
516 
517 
518     /** Request inference with provided Bundle and Params. */
519     public static final int REQUEST_TYPE_INFERENCE = 0;
520 
521     /**
522      * Prepares the remote implementation environment for e.g.loading inference runtime etc
523      * .which
524      * are time consuming beforehand to remove overhead and allow quick processing of requests
525      * thereof.
526      */
527     public static final int REQUEST_TYPE_PREPARE = 1;
528 
529     /** Request Embeddings of the passed-in Bundle. */
530     public static final int REQUEST_TYPE_EMBEDDINGS = 2;
531 
532     /**
533      * @hide
534      */
535     @IntDef(value = {
536             REQUEST_TYPE_INFERENCE,
537             REQUEST_TYPE_PREPARE,
538             REQUEST_TYPE_EMBEDDINGS
539     }, open = true)
540     @Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.PARAMETER,
541             ElementType.FIELD})
542     @Retention(RetentionPolicy.SOURCE)
543     public @interface RequestType {
544     }
545 
546     /**
547      * {@link Bundle}s annotated with this type will be validated that they are in-effect read-only
548      * when passed via Binder IPC. Following restrictions apply :
549      * <ul>
550      * <li> {@link PersistableBundle}s are allowed.</li>
551      * <li> Any primitive types or their collections can be added as usual.</li>
552      * <li>IBinder objects should *not* be added.</li>
553      * <li>Parcelable data which has no active-objects, should be added as
554      * {@link Bundle#putByteArray}</li>
555      * <li>Parcelables have active-objects, only following types will be allowed</li>
556      * <ul>
557      *  <li>{@link android.os.ParcelFileDescriptor} opened in
558      *  {@link android.os.ParcelFileDescriptor#MODE_READ_ONLY}</li>
559      * </ul>
560      * </ul>
561      *
562      * In all other scenarios the system-server might throw a
563      * {@link android.os.BadParcelableException} if the Bundle validation fails.
564      *
565      * @hide
566      */
567     @Target({ElementType.PARAMETER, ElementType.FIELD})
568     public @interface StateParams {
569     }
570 
571     /**
572      * This is an extension of {@link StateParams} but for purpose of inference few other types are
573      * also allowed as read-only, as listed below.
574      *
575      * <li>{@link Bitmap} set as immutable.</li>
576      * <li>{@link android.database.CursorWindow}</li>
577      * <li>{@link android.os.SharedMemory} set to {@link OsConstants#PROT_READ}</li>
578      * </ul>
579      * </ul>
580      *
581      * In all other scenarios the system-server might throw a
582      * {@link android.os.BadParcelableException} if the Bundle validation fails.
583      *
584      * @hide
585      */
586     @Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.TYPE_USE})
587     public @interface InferenceParams {
588     }
589 
590     /**
591      * This is an extension of {@link StateParams} with the exception that it allows writing
592      * {@link Bitmap} as part of the response.
593      *
594      * In all other scenarios the system-server might throw a
595      * {@link android.os.BadParcelableException} if the Bundle validation fails.
596      *
597      * @hide
598      */
599     @Target({ElementType.PARAMETER, ElementType.FIELD})
600     public @interface ResponseParams {
601     }
602 
603     @Nullable
configureRemoteCancellationFuture( @ullable CancellationSignal cancellationSignal, @NonNull Executor callbackExecutor)604     private static AndroidFuture<IBinder> configureRemoteCancellationFuture(
605             @Nullable CancellationSignal cancellationSignal,
606             @NonNull Executor callbackExecutor) {
607         if (cancellationSignal == null) {
608             return null;
609         }
610         AndroidFuture<IBinder> cancellationFuture = new AndroidFuture<>();
611         cancellationFuture.whenCompleteAsync(
612                 (cancellationTransport, error) -> {
613                     if (error != null || cancellationTransport == null) {
614                         Log.e(TAG, "Unable to receive the remote cancellation signal.", error);
615                     } else {
616                         cancellationSignal.setRemote(
617                                 ICancellationSignal.Stub.asInterface(cancellationTransport));
618                     }
619                 }, callbackExecutor);
620         return cancellationFuture;
621     }
622 
623     @Nullable
configureRemoteProcessingSignalFuture( ProcessingSignal processingSignal, Executor executor)624     private static AndroidFuture<IBinder> configureRemoteProcessingSignalFuture(
625             ProcessingSignal processingSignal, Executor executor) {
626         if (processingSignal == null) {
627             return null;
628         }
629         AndroidFuture<IBinder> processingSignalFuture = new AndroidFuture<>();
630         processingSignalFuture.whenCompleteAsync(
631                 (transport, error) -> {
632                     if (error != null || transport == null) {
633                         Log.e(TAG, "Unable to receive the remote processing signal.", error);
634                     } else {
635                         processingSignal.setRemote(IProcessingSignal.Stub.asInterface(transport));
636                     }
637                 }, executor);
638         return processingSignalFuture;
639     }
640 
641 
642 }
643