1 /* 2 * Copyright (C) 2020 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.server.autofill; 18 19 import static com.android.server.autofill.Helper.sDebug; 20 import static com.android.server.autofill.Helper.sVerbose; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.UserIdInt; 25 import android.app.AppGlobals; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.pm.PackageManager; 30 import android.content.pm.ServiceInfo; 31 import android.os.Build; 32 import android.os.ICancellationSignal; 33 import android.os.RemoteException; 34 import android.os.SystemClock; 35 import android.service.assist.classification.FieldClassificationRequest; 36 import android.service.assist.classification.FieldClassificationResponse; 37 import android.service.assist.classification.FieldClassificationService; 38 import android.service.assist.classification.IFieldClassificationCallback; 39 import android.service.assist.classification.IFieldClassificationService; 40 import android.util.Log; 41 import android.util.Pair; 42 import android.util.Slog; 43 44 import com.android.internal.infra.AbstractRemoteService; 45 import com.android.internal.infra.ServiceConnector; 46 47 import java.lang.ref.WeakReference; 48 49 /** 50 * Class responsible for connection with the Remote {@link FieldClassificationService}. 51 * This class is instantiated when {@link AutofillManagerServiceImpl} is established. 52 * The connection is supposed to be bounded forever, as such, this class persists beyond 53 * Autofill {@link Session}'s lifecycle. As such, it can't contain information relevant to Session. 54 * This design is completely different from {@link RemoteFillService}. 55 */ 56 final class RemoteFieldClassificationService 57 extends ServiceConnector.Impl<IFieldClassificationService> { 58 59 private static final String TAG = 60 "Autofill" + RemoteFieldClassificationService.class.getSimpleName(); 61 62 // Bind forever. 63 private static final long TIMEOUT_IDLE_UNBIND_MS = 64 AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS; 65 private final ComponentName mComponentName; 66 67 public interface FieldClassificationServiceCallbacks { onClassificationRequestSuccess(@onNull FieldClassificationResponse response)68 void onClassificationRequestSuccess(@NonNull FieldClassificationResponse response); onClassificationRequestFailure(int requestId, @Nullable CharSequence message)69 void onClassificationRequestFailure(int requestId, @Nullable CharSequence message); onClassificationRequestTimeout(int requestId)70 void onClassificationRequestTimeout(int requestId); onServiceDied(@onNull RemoteFieldClassificationService service)71 void onServiceDied(@NonNull RemoteFieldClassificationService service); logFieldClassificationEvent( long startTime, @NonNull FieldClassificationResponse response, @FieldClassificationEventLogger.FieldClassificationStatus int status)72 void logFieldClassificationEvent( 73 long startTime, @NonNull FieldClassificationResponse response, 74 @FieldClassificationEventLogger.FieldClassificationStatus int status); 75 } 76 RemoteFieldClassificationService(Context context, ComponentName serviceName, int serviceUid, int userId)77 RemoteFieldClassificationService(Context context, ComponentName serviceName, 78 int serviceUid, int userId) { 79 super(context, 80 // TODO(b/266379948): Update service 81 new Intent(FieldClassificationService.SERVICE_INTERFACE).setComponent(serviceName), 82 /* bindingFlags= */ 0, userId, IFieldClassificationService.Stub::asInterface); 83 mComponentName = serviceName; 84 if (sDebug) { 85 Slog.d(TAG, "About to connect to serviceName: " + serviceName); 86 } 87 // Bind right away. 88 connect(); 89 } 90 91 @Nullable getComponentName(@onNull String serviceName, @UserIdInt int userId, boolean isTemporary)92 static Pair<ServiceInfo, ComponentName> getComponentName(@NonNull String serviceName, 93 @UserIdInt int userId, boolean isTemporary) { 94 int flags = PackageManager.GET_META_DATA; 95 if (!isTemporary) { 96 flags |= PackageManager.MATCH_SYSTEM_ONLY; 97 } 98 99 final ComponentName serviceComponent; 100 ServiceInfo serviceInfo = null; 101 try { 102 serviceComponent = ComponentName.unflattenFromString(serviceName); 103 serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, flags, 104 userId); 105 if (serviceInfo == null) { 106 Slog.e(TAG, "Bad service name for flags " + flags + ": " + serviceName); 107 return null; 108 } 109 } catch (Exception e) { 110 Slog.e(TAG, "Error getting service info for '" + serviceName + "': " + e); 111 return null; 112 } 113 return new Pair<>(serviceInfo, serviceComponent); 114 } 115 getComponentName()116 public ComponentName getComponentName() { 117 return mComponentName; 118 } 119 120 @Override // from ServiceConnector.Impl onServiceConnectionStatusChanged(IFieldClassificationService service, boolean connected)121 protected void onServiceConnectionStatusChanged(IFieldClassificationService service, 122 boolean connected) { 123 try { 124 if (connected) { 125 service.onConnected(false, false); 126 } else { 127 service.onDisconnected(); 128 } 129 } catch (Exception e) { 130 Slog.w(TAG, 131 "Exception calling onServiceConnectionStatusChanged(" + connected + "): ", e); 132 } 133 } 134 135 @Override // from AbstractRemoteService getAutoDisconnectTimeoutMs()136 protected long getAutoDisconnectTimeoutMs() { 137 return TIMEOUT_IDLE_UNBIND_MS; 138 } 139 onFieldClassificationRequest(@onNull FieldClassificationRequest request, WeakReference<FieldClassificationServiceCallbacks> fieldClassificationServiceCallbacksWeakRef)140 public void onFieldClassificationRequest(@NonNull FieldClassificationRequest request, 141 WeakReference<FieldClassificationServiceCallbacks> 142 fieldClassificationServiceCallbacksWeakRef) { 143 final long startTime = SystemClock.elapsedRealtime(); 144 if (sVerbose) { 145 Slog.v(TAG, "onFieldClassificationRequest request:" + request); 146 } 147 148 run( 149 (s) -> 150 s.onFieldClassificationRequest( 151 request, 152 new IFieldClassificationCallback.Stub() { 153 @Override 154 public void onCancellable(ICancellationSignal cancellation) { 155 if (sDebug) { 156 Log.d(TAG, "onCancellable"); 157 } 158 FieldClassificationServiceCallbacks 159 fieldClassificationServiceCallbacks = 160 Helper.weakDeref( 161 fieldClassificationServiceCallbacksWeakRef, 162 TAG, "onCancellable " 163 ); 164 logFieldClassificationEvent( 165 startTime, 166 fieldClassificationServiceCallbacks, 167 FieldClassificationEventLogger.STATUS_CANCELLED, 168 null); 169 } 170 171 @Override 172 public void onSuccess(FieldClassificationResponse response) { 173 if (sDebug) { 174 if (Build.IS_DEBUGGABLE) { 175 Slog.d(TAG, "onSuccess Response: " + response); 176 } else { 177 String msg = ""; 178 if (response == null 179 || response.getClassifications() == null) { 180 msg = "null response"; 181 } else { 182 msg = "size: " 183 + response.getClassifications().size(); 184 } 185 Slog.d(TAG, "onSuccess " + msg); 186 } 187 } 188 FieldClassificationServiceCallbacks 189 fieldClassificationServiceCallbacks = 190 Helper.weakDeref( 191 fieldClassificationServiceCallbacksWeakRef, 192 TAG, "onSuccess " 193 ); 194 logFieldClassificationEvent( 195 startTime, 196 fieldClassificationServiceCallbacks, 197 FieldClassificationEventLogger.STATUS_SUCCESS, 198 response); 199 if (fieldClassificationServiceCallbacks == null) { 200 return; 201 } 202 fieldClassificationServiceCallbacks 203 .onClassificationRequestSuccess(response); 204 } 205 206 @Override 207 public void onFailure() { 208 if (sDebug) { 209 Slog.d(TAG, "onFailure"); 210 } 211 FieldClassificationServiceCallbacks 212 fieldClassificationServiceCallbacks = 213 Helper.weakDeref( 214 fieldClassificationServiceCallbacksWeakRef, 215 TAG, "onFailure " 216 ); 217 logFieldClassificationEvent( 218 startTime, 219 fieldClassificationServiceCallbacks, 220 FieldClassificationEventLogger.STATUS_FAIL, 221 null); 222 if (fieldClassificationServiceCallbacks == null) { 223 return; 224 } 225 fieldClassificationServiceCallbacks 226 .onClassificationRequestFailure(0, null); 227 } 228 229 @Override 230 public boolean isCompleted() throws RemoteException { 231 return false; 232 } 233 234 @Override 235 public void cancel() throws RemoteException {} 236 })); 237 } 238 logFieldClassificationEvent( long startTime, @Nullable FieldClassificationServiceCallbacks fieldClassificationServiceCallbacks, @FieldClassificationEventLogger.FieldClassificationStatus int status, FieldClassificationResponse response)239 private void logFieldClassificationEvent( 240 long startTime, 241 @Nullable FieldClassificationServiceCallbacks fieldClassificationServiceCallbacks, 242 @FieldClassificationEventLogger.FieldClassificationStatus int status, 243 FieldClassificationResponse response) { 244 if (fieldClassificationServiceCallbacks == null) { 245 final FieldClassificationEventLogger logger = 246 FieldClassificationEventLogger.createLogger(); 247 logger.startNewLogForRequest(); 248 logger.maybeSetLatencyMillis( 249 SystemClock.elapsedRealtime() - startTime); 250 logger.maybeSetSessionGc(true); 251 logger.maybeSetRequestStatus(status); 252 logger.logAndEndEvent(); 253 } else { 254 fieldClassificationServiceCallbacks.logFieldClassificationEvent( 255 startTime, response, status); 256 } 257 258 } 259 } 260