• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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