1 /*
2  * Copyright (C) 2022 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.ondevicepersonalization.services;
18 
19 import static android.adservices.ondevicepersonalization.OnDevicePersonalizationPermissions.MODIFY_ONDEVICEPERSONALIZATION_STATE;
20 
21 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__API_CALLBACK_ERROR;
22 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__API_REMOTE_EXCEPTION;
23 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ON_DEVICE_PERSONALIZATION_ERROR;
24 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__ODP;
25 
26 import android.adservices.ondevicepersonalization.Constants;
27 import android.adservices.ondevicepersonalization.aidl.IOnDevicePersonalizationConfigService;
28 import android.adservices.ondevicepersonalization.aidl.IOnDevicePersonalizationConfigServiceCallback;
29 import android.annotation.NonNull;
30 import android.annotation.RequiresPermission;
31 import android.content.Context;
32 import android.content.pm.PackageManager;
33 import android.ondevicepersonalization.IOnDevicePersonalizationSystemService;
34 import android.ondevicepersonalization.IOnDevicePersonalizationSystemServiceCallback;
35 import android.ondevicepersonalization.OnDevicePersonalizationSystemServiceManager;
36 import android.os.Binder;
37 import android.os.Bundle;
38 import android.os.RemoteException;
39 
40 import com.android.modules.utils.build.SdkLevel;
41 import com.android.ondevicepersonalization.internal.util.LoggerFactory;
42 import com.android.ondevicepersonalization.services.data.user.RawUserData;
43 import com.android.ondevicepersonalization.services.data.user.UserDataCollector;
44 import com.android.ondevicepersonalization.services.data.user.UserPrivacyStatus;
45 import com.android.ondevicepersonalization.services.statsd.errorlogging.ClientErrorLogger;
46 
47 import java.util.Objects;
48 import java.util.concurrent.Executor;
49 
50 /**
51  * ODP service that modifies and persists ODP enablement status
52  */
53 public class OnDevicePersonalizationConfigServiceDelegate
54         extends IOnDevicePersonalizationConfigService.Stub {
55     private static final LoggerFactory.Logger sLogger = LoggerFactory.getLogger();
56     private static final String TAG = "OnDevicePersonalizationConfigServiceDelegate";
57     private final Context mContext;
58     private static final Executor sBackgroundExecutor =
59             OnDevicePersonalizationExecutors.getBackgroundExecutor();
60     private static final int SERVICE_NOT_IMPLEMENTED = 501;
61 
OnDevicePersonalizationConfigServiceDelegate(Context context)62     public OnDevicePersonalizationConfigServiceDelegate(Context context) {
63         mContext = context;
64     }
65 
66     @Override
67     @RequiresPermission(MODIFY_ONDEVICEPERSONALIZATION_STATE)
setPersonalizationStatus(boolean enabled, @NonNull IOnDevicePersonalizationConfigServiceCallback callback)68     public void setPersonalizationStatus(boolean enabled,
69                                      @NonNull IOnDevicePersonalizationConfigServiceCallback
70                                              callback) {
71         if (getGlobalKillSwitch()) {
72             throw new IllegalStateException("Service skipped as the API flag is turned off.");
73         }
74 
75         // Verify caller's permission
76         if (mContext.checkCallingPermission(MODIFY_ONDEVICEPERSONALIZATION_STATE)
77                 != PackageManager.PERMISSION_GRANTED) {
78             throw new SecurityException(
79                     "Permission denied: " + MODIFY_ONDEVICEPERSONALIZATION_STATE);
80         }
81         Objects.requireNonNull(callback);
82 
83         sBackgroundExecutor.execute(
84                 () -> {
85                     try {
86                         UserPrivacyStatus userPrivacyStatus = UserPrivacyStatus.getInstance();
87 
88                         boolean oldStatus = userPrivacyStatus.isPersonalizationStatusEnabled();
89                         userPrivacyStatus.setPersonalizationStatusEnabled(enabled);
90                         boolean newStatus = userPrivacyStatus.isPersonalizationStatusEnabled();
91 
92                         if (oldStatus == newStatus) {
93                             sendSuccess(callback);
94                             return;
95                         }
96 
97                         // Rollback all user data if personalization status changes
98                         RawUserData userData = RawUserData.getInstance();
99                         UserDataCollector userDataCollector =
100                                 UserDataCollector.getInstance(mContext);
101                         userDataCollector.clearUserData(userData);
102                         userDataCollector.clearMetadata();
103 
104                         // TODO(b/302018665): replicate system server storage to T devices.
105                         if (!SdkLevel.isAtLeastU()) {
106                             userPrivacyStatus.setPersonalizationStatusEnabled(enabled);
107                             sendSuccess(callback);
108                             return;
109                         }
110                         // Persist in the system server for U+ devices
111                         OnDevicePersonalizationSystemServiceManager systemServiceManager =
112                                 mContext.getSystemService(
113                                         OnDevicePersonalizationSystemServiceManager.class);
114                         // Cannot find system server on U+.
115                         if (systemServiceManager == null) {
116                             sendError(callback, SERVICE_NOT_IMPLEMENTED);
117                             return;
118                         }
119                         IOnDevicePersonalizationSystemService systemService =
120                                 systemServiceManager.getService();
121                         // The system service is not ready.
122                         if (systemService == null) {
123                             sendError(callback, SERVICE_NOT_IMPLEMENTED);
124                             return;
125                         }
126                         try {
127                             systemService.setPersonalizationStatus(
128                                     enabled,
129                                     new IOnDevicePersonalizationSystemServiceCallback.Stub() {
130                                         @Override
131                                         public void onResult(Bundle bundle) throws RemoteException {
132                                             userPrivacyStatus.setPersonalizationStatusEnabled(
133                                                     enabled);
134                                             callback.onSuccess();
135                                         }
136 
137                                         @Override
138                                         public void onError(int errorCode) throws RemoteException {
139                                             callback.onFailure(errorCode);
140                                         }
141                                     });
142                         } catch (RemoteException re) {
143                             sLogger.e(TAG + ": Unable to send result to the callback.", re);
144                             ClientErrorLogger.getInstance()
145                                     .logErrorWithExceptionInfo(
146                                             re,
147                                             AD_SERVICES_ERROR_REPORTED__ERROR_CODE__API_REMOTE_EXCEPTION,
148                                             AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__ODP);
149                         }
150                     } catch (Exception e) {
151                         sLogger.e(TAG + ": Failed to set personalization status.", e);
152                         ClientErrorLogger.getInstance()
153                                 .logErrorWithExceptionInfo(
154                                         e,
155                                         AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ON_DEVICE_PERSONALIZATION_ERROR,
156                                         AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__ODP);
157                         sendError(callback, Constants.STATUS_INTERNAL_ERROR);
158                     }
159                 });
160     }
161 
sendSuccess( @onNull IOnDevicePersonalizationConfigServiceCallback callback)162     private void sendSuccess(
163             @NonNull IOnDevicePersonalizationConfigServiceCallback callback) {
164         try {
165             callback.onSuccess();
166         } catch (RemoteException e) {
167             sLogger.e(TAG + ": Callback error", e);
168             ClientErrorLogger.getInstance()
169                     .logErrorWithExceptionInfo(
170                             e,
171                             AD_SERVICES_ERROR_REPORTED__ERROR_CODE__API_CALLBACK_ERROR,
172                             AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__ODP);
173         }
174     }
175 
sendError( @onNull IOnDevicePersonalizationConfigServiceCallback callback, int errorCode)176     private void sendError(
177             @NonNull IOnDevicePersonalizationConfigServiceCallback callback, int errorCode) {
178         try {
179             callback.onFailure(errorCode);
180         } catch (RemoteException e) {
181             sLogger.e(TAG + ": Callback error", e);
182             ClientErrorLogger.getInstance()
183                     .logErrorWithExceptionInfo(
184                             e,
185                             AD_SERVICES_ERROR_REPORTED__ERROR_CODE__API_CALLBACK_ERROR,
186                             AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__ODP);
187         }
188     }
189 
getGlobalKillSwitch()190     private boolean getGlobalKillSwitch() {
191         long origId = Binder.clearCallingIdentity();
192         boolean globalKillSwitch = FlagsFactory.getFlags().getGlobalKillSwitch();
193         Binder.restoreCallingIdentity(origId);
194         return globalKillSwitch;
195     }
196 }
197