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 package com.android.server.autofill; 17 18 import static com.android.server.autofill.Helper.sVerbose; 19 20 import android.Manifest; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.UserIdInt; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.pm.PackageManager; 28 import android.content.pm.ResolveInfo; 29 import android.content.pm.ServiceInfo; 30 import android.os.Bundle; 31 import android.os.IBinder; 32 import android.os.RemoteCallback; 33 import android.service.autofill.IInlineSuggestionRenderService; 34 import android.service.autofill.IInlineSuggestionUiCallback; 35 import android.service.autofill.InlinePresentation; 36 import android.service.autofill.InlineSuggestionRenderService; 37 import android.util.Slog; 38 39 import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; 40 41 /** 42 * Remote service to help connect to InlineSuggestionRenderService in ExtServices. 43 */ 44 public final class RemoteInlineSuggestionRenderService extends 45 AbstractMultiplePendingRequestsRemoteService<RemoteInlineSuggestionRenderService, 46 IInlineSuggestionRenderService> { 47 48 private static final String TAG = "RemoteInlineSuggestionRenderService"; 49 50 private final long mIdleUnbindTimeoutMs = PERMANENT_BOUND_TIMEOUT_MS; 51 RemoteInlineSuggestionRenderService(Context context, ComponentName componentName, String serviceInterface, int userId, InlineSuggestionRenderCallbacks callback, boolean bindInstantServiceAllowed, boolean verbose)52 RemoteInlineSuggestionRenderService(Context context, ComponentName componentName, 53 String serviceInterface, int userId, InlineSuggestionRenderCallbacks callback, 54 boolean bindInstantServiceAllowed, boolean verbose) { 55 super(context, serviceInterface, componentName, userId, callback, 56 context.getMainThreadHandler(), 57 bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0, verbose, 58 /* initialCapacity= */ 2); 59 60 ensureBound(); 61 } 62 63 @Override // from AbstractRemoteService getServiceInterface(@onNull IBinder service)64 protected IInlineSuggestionRenderService getServiceInterface(@NonNull IBinder service) { 65 return IInlineSuggestionRenderService.Stub.asInterface(service); 66 } 67 68 @Override // from AbstractRemoteService getTimeoutIdleBindMillis()69 protected long getTimeoutIdleBindMillis() { 70 return mIdleUnbindTimeoutMs; 71 } 72 73 @Override // from AbstractRemoteService handleOnConnectedStateChanged(boolean connected)74 protected void handleOnConnectedStateChanged(boolean connected) { 75 if (connected && getTimeoutIdleBindMillis() != PERMANENT_BOUND_TIMEOUT_MS) { 76 scheduleUnbind(); 77 } 78 super.handleOnConnectedStateChanged(connected); 79 } 80 ensureBound()81 public void ensureBound() { 82 scheduleBind(); 83 } 84 85 /** 86 * Called by {@link Session} to generate a call to the 87 * {@link RemoteInlineSuggestionRenderService} to request rendering a slice . 88 */ renderSuggestion(@onNull IInlineSuggestionUiCallback callback, @NonNull InlinePresentation presentation, int width, int height, @Nullable IBinder hostInputToken, int displayId, int userId, int sessionId)89 public void renderSuggestion(@NonNull IInlineSuggestionUiCallback callback, 90 @NonNull InlinePresentation presentation, int width, int height, 91 @Nullable IBinder hostInputToken, int displayId, int userId, int sessionId) { 92 scheduleAsyncRequest((s) -> s.renderSuggestion(callback, presentation, width, height, 93 hostInputToken, displayId, userId, sessionId)); 94 } 95 96 /** 97 * Gets the inline suggestions renderer info as a {@link Bundle}. 98 */ getInlineSuggestionsRendererInfo(@onNull RemoteCallback callback)99 public void getInlineSuggestionsRendererInfo(@NonNull RemoteCallback callback) { 100 scheduleAsyncRequest((s) -> s.getInlineSuggestionsRendererInfo(callback)); 101 } 102 103 /** 104 * Destroys the remote inline suggestion views associated with the given user id and session id. 105 */ destroySuggestionViews(int userId, int sessionId)106 public void destroySuggestionViews(int userId, int sessionId) { 107 scheduleAsyncRequest((s) -> s.destroySuggestionViews(userId, sessionId)); 108 } 109 110 @Nullable getServiceInfo(Context context, int userId)111 private static ServiceInfo getServiceInfo(Context context, int userId) { 112 final String packageName = 113 context.getPackageManager().getServicesSystemSharedLibraryPackageName(); 114 if (packageName == null) { 115 Slog.w(TAG, "no external services package!"); 116 return null; 117 } 118 119 final Intent intent = new Intent(InlineSuggestionRenderService.SERVICE_INTERFACE); 120 intent.setPackage(packageName); 121 final ResolveInfo resolveInfo = context.getPackageManager().resolveServiceAsUser(intent, 122 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, userId); 123 final ServiceInfo serviceInfo = resolveInfo == null ? null : resolveInfo.serviceInfo; 124 if (resolveInfo == null || serviceInfo == null) { 125 Slog.w(TAG, "No valid components found."); 126 return null; 127 } 128 129 if (!Manifest.permission.BIND_INLINE_SUGGESTION_RENDER_SERVICE 130 .equals(serviceInfo.permission)) { 131 Slog.w(TAG, serviceInfo.name + " does not require permission " 132 + Manifest.permission.BIND_INLINE_SUGGESTION_RENDER_SERVICE); 133 return null; 134 } 135 136 return serviceInfo; 137 } 138 139 @Nullable getServiceComponentName(Context context, @UserIdInt int userId)140 public static ComponentName getServiceComponentName(Context context, @UserIdInt int userId) { 141 final ServiceInfo serviceInfo = getServiceInfo(context, userId); 142 if (serviceInfo == null) return null; 143 144 final ComponentName componentName = new ComponentName(serviceInfo.packageName, 145 serviceInfo.name); 146 147 if (sVerbose) Slog.v(TAG, "getServiceComponentName(): " + componentName); 148 return componentName; 149 } 150 151 interface InlineSuggestionRenderCallbacks 152 extends VultureCallback<RemoteInlineSuggestionRenderService> { 153 // NOTE: so far we don't need to notify the callback implementation 154 // (AutofillManagerServiceImpl) of the request results (success, timeouts, etc..), so this 155 // callback interface is empty. 156 } 157 } 158