blob: 5ce8145fa00e707384385e6928fb5dbe9734eb29 [file] [log] [blame]
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -08001/*
2 * Copyright (C) 2018 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
17package com.android.server.textclassifier;
18
Eugene Susla7b24b2b2018-03-16 14:33:31 -070019import android.annotation.NonNull;
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +000020import android.annotation.Nullable;
Eugene Susla7b24b2b2018-03-16 14:33:31 -070021import android.annotation.UserIdInt;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080022import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
25import android.content.ServiceConnection;
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +000026import android.content.pm.PackageManager;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080027import android.os.Binder;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080028import android.os.IBinder;
29import android.os.RemoteException;
Eugene Susla7b24b2b2018-03-16 14:33:31 -070030import android.os.UserHandle;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080031import android.service.textclassifier.ITextClassificationCallback;
Eugene Susla7b24b2b2018-03-16 14:33:31 -070032import android.service.textclassifier.ITextClassifierService;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080033import android.service.textclassifier.ITextLinksCallback;
34import android.service.textclassifier.ITextSelectionCallback;
35import android.service.textclassifier.TextClassifierService;
Eugene Susla7b24b2b2018-03-16 14:33:31 -070036import android.util.Slog;
37import android.util.SparseArray;
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +000038import android.view.textclassifier.SelectionEvent;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080039import android.view.textclassifier.TextClassification;
Abodunrinwa Toki080c8542018-03-27 00:04:06 +010040import android.view.textclassifier.TextClassificationContext;
Tony Makf93e9e52018-07-16 14:46:29 +020041import android.view.textclassifier.TextClassificationManager;
Abodunrinwa Toki080c8542018-03-27 00:04:06 +010042import android.view.textclassifier.TextClassificationSessionId;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080043import android.view.textclassifier.TextLinks;
44import android.view.textclassifier.TextSelection;
45
46import com.android.internal.annotations.GuardedBy;
Tony Makf93e9e52018-07-16 14:46:29 +020047import com.android.internal.util.DumpUtils;
Eugene Susla7b24b2b2018-03-16 14:33:31 -070048import com.android.internal.util.FunctionalUtils;
49import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
Tony Makf93e9e52018-07-16 14:46:29 +020050import com.android.internal.util.IndentingPrintWriter;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080051import com.android.internal.util.Preconditions;
52import com.android.server.SystemService;
53
Tony Makf93e9e52018-07-16 14:46:29 +020054import java.io.FileDescriptor;
55import java.io.PrintWriter;
Eugene Susla7b24b2b2018-03-16 14:33:31 -070056import java.util.ArrayDeque;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080057import java.util.Queue;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080058
59/**
60 * A manager for TextClassifier services.
61 * Apps bind to the TextClassificationManagerService for text classification. This service
62 * reroutes calls to it to a {@link TextClassifierService} that it manages.
63 */
64public final class TextClassificationManagerService extends ITextClassifierService.Stub {
65
66 private static final String LOG_TAG = "TextClassificationManagerService";
67
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080068 public static final class Lifecycle extends SystemService {
69
70 private final TextClassificationManagerService mManagerService;
71
72 public Lifecycle(Context context) {
73 super(context);
74 mManagerService = new TextClassificationManagerService(context);
75 }
76
77 @Override
78 public void onStart() {
79 try {
80 publishBinderService(Context.TEXT_CLASSIFICATION_SERVICE, mManagerService);
81 } catch (Throwable t) {
82 // Starting this service is not critical to the running of this device and should
83 // therefore not crash the device. If it fails, log the error and continue.
84 Slog.e(LOG_TAG, "Could not start the TextClassificationManagerService.", t);
85 }
86 }
Eugene Susla7b24b2b2018-03-16 14:33:31 -070087
88 @Override
89 public void onStartUser(int userId) {
90 processAnyPendingWork(userId);
91 }
92
93 @Override
94 public void onUnlockUser(int userId) {
95 // Rebind if we failed earlier due to locked encrypted user
96 processAnyPendingWork(userId);
97 }
98
99 private void processAnyPendingWork(int userId) {
100 synchronized (mManagerService.mLock) {
101 mManagerService.getUserStateLocked(userId).bindIfHasPendingRequestsLocked();
102 }
103 }
104
105 @Override
106 public void onStopUser(int userId) {
107 synchronized (mManagerService.mLock) {
108 UserState userState = mManagerService.peekUserStateLocked(userId);
109 if (userState != null) {
110 userState.mConnection.cleanupService();
111 mManagerService.mUserStates.remove(userId);
112 }
113 }
114 }
115
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800116 }
117
118 private final Context mContext;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800119 private final Object mLock;
120 @GuardedBy("mLock")
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700121 final SparseArray<UserState> mUserStates = new SparseArray<>();
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800122
123 private TextClassificationManagerService(Context context) {
124 mContext = Preconditions.checkNotNull(context);
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800125 mLock = new Object();
126 }
127
128 @Override
129 public void onSuggestSelection(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100130 TextClassificationSessionId sessionId,
131 TextSelection.Request request, ITextSelectionCallback callback)
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800132 throws RemoteException {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100133 Preconditions.checkNotNull(request);
134 Preconditions.checkNotNull(callback);
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800135
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800136 synchronized (mLock) {
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700137 UserState userState = getCallingUserStateLocked();
138 if (!userState.bindLocked()) {
139 callback.onFailure();
140 } else if (userState.isBoundLocked()) {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100141 userState.mService.onSuggestSelection(sessionId, request, callback);
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800142 } else {
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700143 userState.mPendingRequests.add(new PendingRequest(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100144 () -> onSuggestSelection(sessionId, request, callback),
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700145 callback::onFailure, callback.asBinder(), this, userState));
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800146 }
147 }
148 }
149
150 @Override
151 public void onClassifyText(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100152 TextClassificationSessionId sessionId,
153 TextClassification.Request request, ITextClassificationCallback callback)
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800154 throws RemoteException {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100155 Preconditions.checkNotNull(request);
156 Preconditions.checkNotNull(callback);
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800157
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800158 synchronized (mLock) {
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700159 UserState userState = getCallingUserStateLocked();
160 if (!userState.bindLocked()) {
161 callback.onFailure();
162 } else if (userState.isBoundLocked()) {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100163 userState.mService.onClassifyText(sessionId, request, callback);
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800164 } else {
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700165 userState.mPendingRequests.add(new PendingRequest(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100166 () -> onClassifyText(sessionId, request, callback),
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700167 callback::onFailure, callback.asBinder(), this, userState));
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800168 }
169 }
170 }
171
172 @Override
173 public void onGenerateLinks(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100174 TextClassificationSessionId sessionId,
175 TextLinks.Request request, ITextLinksCallback callback)
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800176 throws RemoteException {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100177 Preconditions.checkNotNull(request);
178 Preconditions.checkNotNull(callback);
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800179
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800180 synchronized (mLock) {
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700181 UserState userState = getCallingUserStateLocked();
182 if (!userState.bindLocked()) {
183 callback.onFailure();
184 } else if (userState.isBoundLocked()) {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100185 userState.mService.onGenerateLinks(sessionId, request, callback);
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800186 } else {
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700187 userState.mPendingRequests.add(new PendingRequest(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100188 () -> onGenerateLinks(sessionId, request, callback),
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700189 callback::onFailure, callback.asBinder(), this, userState));
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800190 }
191 }
192 }
193
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000194 @Override
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100195 public void onSelectionEvent(
196 TextClassificationSessionId sessionId, SelectionEvent event) throws RemoteException {
197 Preconditions.checkNotNull(event);
198 validateInput(event.getPackageName(), mContext);
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000199
200 synchronized (mLock) {
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700201 UserState userState = getCallingUserStateLocked();
202 if (userState.isBoundLocked()) {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100203 userState.mService.onSelectionEvent(sessionId, event);
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000204 } else {
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700205 userState.mPendingRequests.add(new PendingRequest(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100206 () -> onSelectionEvent(sessionId, event),
207 null /* onServiceFailure */, null /* binder */, this, userState));
208 }
209 }
210 }
211
212 @Override
213 public void onCreateTextClassificationSession(
214 TextClassificationContext classificationContext, TextClassificationSessionId sessionId)
215 throws RemoteException {
216 Preconditions.checkNotNull(sessionId);
217 Preconditions.checkNotNull(classificationContext);
218 validateInput(classificationContext.getPackageName(), mContext);
219
220 synchronized (mLock) {
221 UserState userState = getCallingUserStateLocked();
222 if (userState.isBoundLocked()) {
223 userState.mService.onCreateTextClassificationSession(
224 classificationContext, sessionId);
225 } else {
226 userState.mPendingRequests.add(new PendingRequest(
227 () -> onCreateTextClassificationSession(classificationContext, sessionId),
228 null /* onServiceFailure */, null /* binder */, this, userState));
229 }
230 }
231 }
232
233 @Override
234 public void onDestroyTextClassificationSession(TextClassificationSessionId sessionId)
235 throws RemoteException {
236 Preconditions.checkNotNull(sessionId);
237
238 synchronized (mLock) {
239 UserState userState = getCallingUserStateLocked();
240 if (userState.isBoundLocked()) {
241 userState.mService.onDestroyTextClassificationSession(sessionId);
242 } else {
243 userState.mPendingRequests.add(new PendingRequest(
244 () -> onDestroyTextClassificationSession(sessionId),
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700245 null /* onServiceFailure */, null /* binder */, this, userState));
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000246 }
247 }
248 }
249
Andreas Gamped6d42062018-07-20 13:08:21 -0700250 @GuardedBy("mLock")
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700251 private UserState getCallingUserStateLocked() {
252 return getUserStateLocked(UserHandle.getCallingUserId());
253 }
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800254
Andreas Gamped6d42062018-07-20 13:08:21 -0700255 @GuardedBy("mLock")
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700256 private UserState getUserStateLocked(int userId) {
257 UserState result = mUserStates.get(userId);
258 if (result == null) {
259 result = new UserState(userId, mContext, mLock);
260 mUserStates.put(userId, result);
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800261 }
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700262 return result;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800263 }
264
Andreas Gamped6d42062018-07-20 13:08:21 -0700265 @GuardedBy("mLock")
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700266 UserState peekUserStateLocked(int userId) {
267 return mUserStates.get(userId);
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800268 }
269
Tony Makf93e9e52018-07-16 14:46:29 +0200270 @Override
271 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
272 if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, fout)) return;
273 IndentingPrintWriter pw = new IndentingPrintWriter(fout, " ");
274 TextClassificationManager tcm = mContext.getSystemService(TextClassificationManager.class);
275 tcm.dump(pw);
Felipe Lemef8192132018-10-12 13:42:40 -0700276
277 pw.printPair("context", mContext); pw.println();
278 synchronized (mLock) {
279 int size = mUserStates.size();
280 pw.print("Number user states: "); pw.println(size);
281 if (size > 0) {
282 for (int i = 0; i < size; i++) {
283 pw.increaseIndent();
284 UserState userState = mUserStates.valueAt(i);
285 pw.print(i); pw.print(":"); userState.dump(pw); pw.println();
286 pw.decreaseIndent();
287 }
288 }
289 }
Tony Makf93e9e52018-07-16 14:46:29 +0200290 }
291
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700292 private static final class PendingRequest implements IBinder.DeathRecipient {
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800293
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000294 @Nullable private final IBinder mBinder;
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700295 @NonNull private final Runnable mRequest;
296 @Nullable private final Runnable mOnServiceFailure;
297 @GuardedBy("mLock")
298 @NonNull private final UserState mOwningUser;
299 @NonNull private final TextClassificationManagerService mService;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800300
301 /**
302 * Initializes a new pending request.
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800303 * @param request action to perform when the service is bound
304 * @param onServiceFailure action to perform when the service dies or disconnects
305 * @param binder binder to the process that made this pending request
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700306 * @param service
307 * @param owningUser
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800308 */
309 PendingRequest(
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700310 @NonNull ThrowingRunnable request, @Nullable ThrowingRunnable onServiceFailure,
311 @Nullable IBinder binder,
312 TextClassificationManagerService service,
313 UserState owningUser) {
314 mRequest =
315 logOnFailure(Preconditions.checkNotNull(request), "handling pending request");
316 mOnServiceFailure =
317 logOnFailure(onServiceFailure, "notifying callback of service failure");
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000318 mBinder = binder;
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700319 mService = service;
320 mOwningUser = owningUser;
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000321 if (mBinder != null) {
322 try {
323 mBinder.linkToDeath(this, 0);
324 } catch (RemoteException e) {
325 e.printStackTrace();
326 }
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800327 }
328 }
329
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800330 @Override
331 public void binderDied() {
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700332 synchronized (mService.mLock) {
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800333 // No need to handle this pending request anymore. Remove.
334 removeLocked();
335 }
336 }
337
338 @GuardedBy("mLock")
339 private void removeLocked() {
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700340 mOwningUser.mPendingRequests.remove(this);
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000341 if (mBinder != null) {
342 mBinder.unlinkToDeath(this, 0);
343 }
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800344 }
345 }
346
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700347 private static Runnable logOnFailure(@Nullable ThrowingRunnable r, String opDesc) {
348 if (r == null) return null;
349 return FunctionalUtils.handleExceptions(r,
350 e -> Slog.d(LOG_TAG, "Error " + opDesc + ": " + e.getMessage()));
351 }
352
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100353 private static void validateInput(String packageName, Context context)
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000354 throws RemoteException {
355 try {
356 final int uid = context.getPackageManager()
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100357 .getPackageUid(packageName, 0);
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000358 Preconditions.checkArgument(Binder.getCallingUid() == uid);
359 } catch (IllegalArgumentException | NullPointerException |
360 PackageManager.NameNotFoundException e) {
361 throw new RemoteException(e.getMessage());
362 }
363 }
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700364
365 private static final class UserState {
366 @UserIdInt final int mUserId;
367 final TextClassifierServiceConnection mConnection = new TextClassifierServiceConnection();
368 @GuardedBy("mLock")
369 final Queue<PendingRequest> mPendingRequests = new ArrayDeque<>();
370 @GuardedBy("mLock")
371 ITextClassifierService mService;
372 @GuardedBy("mLock")
373 boolean mBinding;
374
375 private final Context mContext;
376 private final Object mLock;
377
378 private UserState(int userId, Context context, Object lock) {
379 mUserId = userId;
380 mContext = Preconditions.checkNotNull(context);
381 mLock = Preconditions.checkNotNull(lock);
382 }
383
384 @GuardedBy("mLock")
385 boolean isBoundLocked() {
386 return mService != null;
387 }
388
389 @GuardedBy("mLock")
390 private void handlePendingRequestsLocked() {
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700391 PendingRequest request;
392 while ((request = mPendingRequests.poll()) != null) {
393 if (isBoundLocked()) {
394 request.mRequest.run();
395 } else {
396 if (request.mOnServiceFailure != null) {
397 request.mOnServiceFailure.run();
398 }
399 }
400
401 if (request.mBinder != null) {
402 request.mBinder.unlinkToDeath(request, 0);
403 }
404 }
405 }
406
Andreas Gamped6d42062018-07-20 13:08:21 -0700407 @GuardedBy("mLock")
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700408 private boolean bindIfHasPendingRequestsLocked() {
409 return !mPendingRequests.isEmpty() && bindLocked();
410 }
411
412 /**
413 * @return true if the service is bound or in the process of being bound.
414 * Returns false otherwise.
415 */
Andreas Gamped6d42062018-07-20 13:08:21 -0700416 @GuardedBy("mLock")
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700417 private boolean bindLocked() {
418 if (isBoundLocked() || mBinding) {
419 return true;
420 }
421
422 // TODO: Handle bind timeout.
423 final boolean willBind;
424 final long identity = Binder.clearCallingIdentity();
425 try {
426 ComponentName componentName =
427 TextClassifierService.getServiceComponentName(mContext);
428 if (componentName == null) {
429 // Might happen if the storage is encrypted and the user is not unlocked
430 return false;
431 }
432 Intent serviceIntent = new Intent(TextClassifierService.SERVICE_INTERFACE)
433 .setComponent(componentName);
434 Slog.d(LOG_TAG, "Binding to " + serviceIntent.getComponent());
435 willBind = mContext.bindServiceAsUser(
436 serviceIntent, mConnection,
437 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
438 UserHandle.of(mUserId));
439 mBinding = willBind;
440 } finally {
441 Binder.restoreCallingIdentity(identity);
442 }
443 return willBind;
444 }
445
Felipe Lemef8192132018-10-12 13:42:40 -0700446 private void dump(IndentingPrintWriter pw) {
447 pw.printPair("context", mContext);
448 pw.printPair("userId", mUserId);
449 synchronized (mLock) {
450 pw.printPair("binding", mBinding);
451 pw.printPair("numberRequests", mPendingRequests.size());
452 }
453 }
454
Eugene Susla7b24b2b2018-03-16 14:33:31 -0700455 private final class TextClassifierServiceConnection implements ServiceConnection {
456 @Override
457 public void onServiceConnected(ComponentName name, IBinder service) {
458 init(ITextClassifierService.Stub.asInterface(service));
459 }
460
461 @Override
462 public void onServiceDisconnected(ComponentName name) {
463 cleanupService();
464 }
465
466 @Override
467 public void onBindingDied(ComponentName name) {
468 cleanupService();
469 }
470
471 @Override
472 public void onNullBinding(ComponentName name) {
473 cleanupService();
474 }
475
476 void cleanupService() {
477 init(null);
478 }
479
480 private void init(@Nullable ITextClassifierService service) {
481 synchronized (mLock) {
482 mService = service;
483 mBinding = false;
484 handlePendingRequestsLocked();
485 }
486 }
487 }
488 }
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800489}