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 android.federatedcompute;
18 
19 import static android.federatedcompute.common.ClientConstants.STATUS_SUCCESS;
20 
21 import android.annotation.NonNull;
22 import android.app.Service;
23 import android.content.Intent;
24 import android.federatedcompute.aidl.IFederatedComputeCallback;
25 import android.federatedcompute.aidl.IResultHandlingService;
26 import android.os.Bundle;
27 import android.os.IBinder;
28 import android.os.RemoteException;
29 
30 import com.android.federatedcompute.internal.util.LogUtil;
31 
32 import java.util.function.Consumer;
33 
34 /**
35  * The abstract base class that client apps need to implement to handle training results.
36  *
37  * <p>The client app will add a {@code <service>} entry to their manifest so that FederatedCompute
38  * API can bind to the their implementation, like so:
39  *
40  * <pre>{@code
41  * <application>
42  *   <service android:enabled="true" android:exported="true" android:name=".YourServiceClass">
43  *     <intent-filter>
44  *       <action android:name="android.federatedcompute.COMPUTATION_RESULT" />
45  *       <data android:scheme="app" />
46  *     </intent-filter>
47  *   </service>
48  * </application>
49  * }</pre>
50  *
51  * @hide
52  */
53 public abstract class ResultHandlingService extends Service {
54     private static final String TAG = "ResultHandlingService";
55     private IBinder mIBinder;
56 
57     @Override
onCreate()58     public void onCreate() {
59         mIBinder = new ServiceBinder();
60     }
61 
62     @Override
onBind(Intent intent)63     public IBinder onBind(Intent intent) {
64         return mIBinder;
65     }
66 
67     private class ServiceBinder extends IResultHandlingService.Stub {
68         @Override
handleResult(Bundle params, IFederatedComputeCallback callback)69         public void handleResult(Bundle params, IFederatedComputeCallback callback) {
70             ResultHandlingService.this.handleResult(params, new ResultHandlingCallback(callback));
71         }
72     }
73 
74     /** A callback for the user to communicate if the results handling is successful. */
75     private static final class ResultHandlingCallback implements Consumer<Integer> {
76         private final IFederatedComputeCallback mInternalCallback;
77 
78         /** Constructor for this */
ResultHandlingCallback(IFederatedComputeCallback internalCallback)79         ResultHandlingCallback(IFederatedComputeCallback internalCallback) {
80             this.mInternalCallback = internalCallback;
81         }
82 
83         /**
84          * Should be called when finished handling results in your {@link ResultHandlingService}
85          * implementation.
86          */
87         @Override
accept(Integer status)88         public void accept(Integer status) {
89             try {
90                 if (status == STATUS_SUCCESS) {
91                     mInternalCallback.onSuccess();
92                     return;
93                 }
94                 mInternalCallback.onFailure(status);
95             } catch (RemoteException e) {
96                 LogUtil.w(
97                         TAG, "An error occurred when trying to communicate with FederatedCompute.");
98             }
99         }
100     }
101 
102     /**
103      * The client app needs to implement this method to handle results. After handling the results,
104      * the client app should signal FederatedCompute via the ResultHandlingCallback.
105      */
handleResult(@onNull Bundle params, Consumer<Integer> callback)106     public abstract void handleResult(@NonNull Bundle params, Consumer<Integer> callback);
107 }
108