1 /* 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 package com.android.server.contentcapture; 17 18 import static android.view.contentcapture.ContentCaptureHelper.sDebug; 19 import static android.view.contentcapture.ContentCaptureHelper.sVerbose; 20 21 import static com.android.server.contentcapture.ContentCaptureMetricsLogger.writeServiceEvent; 22 import static com.android.server.contentcapture.ContentCaptureMetricsLogger.writeSessionEvent; 23 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.os.IBinder; 29 import android.service.contentcapture.ActivityEvent; 30 import android.service.contentcapture.IContentCaptureService; 31 import android.service.contentcapture.IContentCaptureServiceCallback; 32 import android.service.contentcapture.SnapshotData; 33 import android.util.Slog; 34 import android.util.StatsLog; 35 import android.view.contentcapture.ContentCaptureContext; 36 import android.view.contentcapture.DataRemovalRequest; 37 38 import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; 39 import com.android.internal.os.IResultReceiver; 40 41 final class RemoteContentCaptureService 42 extends AbstractMultiplePendingRequestsRemoteService<RemoteContentCaptureService, 43 IContentCaptureService> { 44 45 private final IBinder mServerCallback; 46 private final int mIdleUnbindTimeoutMs; 47 private final ContentCapturePerUserService mPerUserService; 48 RemoteContentCaptureService(Context context, String serviceInterface, ComponentName serviceComponentName, IContentCaptureServiceCallback callback, int userId, ContentCapturePerUserService perUserService, boolean bindInstantServiceAllowed, boolean verbose, int idleUnbindTimeoutMs)49 RemoteContentCaptureService(Context context, String serviceInterface, 50 ComponentName serviceComponentName, IContentCaptureServiceCallback callback, int userId, 51 ContentCapturePerUserService perUserService, boolean bindInstantServiceAllowed, 52 boolean verbose, int idleUnbindTimeoutMs) { 53 super(context, serviceInterface, serviceComponentName, userId, perUserService, 54 context.getMainThreadHandler(), 55 bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0, verbose, 56 /* initialCapacity= */ 2); 57 mPerUserService = perUserService; 58 mServerCallback = callback.asBinder(); 59 mIdleUnbindTimeoutMs = idleUnbindTimeoutMs; 60 61 // Bind right away, which will trigger a onConnected() on service's 62 ensureBoundLocked(); 63 } 64 65 @Override // from AbstractRemoteService getServiceInterface(@onNull IBinder service)66 protected IContentCaptureService getServiceInterface(@NonNull IBinder service) { 67 return IContentCaptureService.Stub.asInterface(service); 68 } 69 70 @Override // from AbstractRemoteService getTimeoutIdleBindMillis()71 protected long getTimeoutIdleBindMillis() { 72 return mIdleUnbindTimeoutMs; 73 } 74 75 @Override // from AbstractRemoteService handleOnConnectedStateChanged(boolean connected)76 protected void handleOnConnectedStateChanged(boolean connected) { 77 if (connected && getTimeoutIdleBindMillis() != PERMANENT_BOUND_TIMEOUT_MS) { 78 scheduleUnbind(); 79 } 80 try { 81 if (connected) { 82 try { 83 mService.onConnected(mServerCallback, sVerbose, sDebug); 84 writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_CONNECTED, 85 mComponentName); 86 } finally { 87 // Update the system-service state, in case the service reconnected after 88 // dying 89 mPerUserService.onConnected(); 90 } 91 } else { 92 mService.onDisconnected(); 93 writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_DISCONNECTED, 94 mComponentName); 95 } 96 } catch (Exception e) { 97 Slog.w(mTag, "Exception calling onConnectedStateChanged(" + connected + "): " + e); 98 } 99 } 100 ensureBoundLocked()101 public void ensureBoundLocked() { 102 scheduleBind(); 103 } 104 105 /** 106 * Called by {@link ContentCaptureServerSession} to generate a call to the 107 * {@link RemoteContentCaptureService} to indicate the session was created. 108 */ onSessionStarted(@ullable ContentCaptureContext context, int sessionId, int uid, @NonNull IResultReceiver clientReceiver, int initialState)109 public void onSessionStarted(@Nullable ContentCaptureContext context, int sessionId, int uid, 110 @NonNull IResultReceiver clientReceiver, int initialState) { 111 scheduleAsyncRequest( 112 (s) -> s.onSessionStarted(context, sessionId, uid, clientReceiver, initialState)); 113 // Metrics logging. 114 writeSessionEvent(sessionId, 115 StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__ON_SESSION_STARTED, initialState, 116 getComponentName(), context.getActivityComponent(), /* is_child_session= */ false); 117 } 118 119 /** 120 * Called by {@link ContentCaptureServerSession} to generate a call to the 121 * {@link RemoteContentCaptureService} to indicate the session was finished. 122 */ onSessionFinished(int sessionId)123 public void onSessionFinished(int sessionId) { 124 scheduleAsyncRequest((s) -> s.onSessionFinished(sessionId)); 125 // Metrics logging. 126 writeSessionEvent(sessionId, 127 StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__ON_SESSION_FINISHED, 128 /* flags= */ 0, getComponentName(), /* app= */ null, 129 /* is_child_session= */ false); 130 } 131 132 /** 133 * Called by {@link ContentCaptureServerSession} to send snapshot data to the service. 134 */ onActivitySnapshotRequest(int sessionId, @NonNull SnapshotData snapshotData)135 public void onActivitySnapshotRequest(int sessionId, @NonNull SnapshotData snapshotData) { 136 scheduleAsyncRequest((s) -> s.onActivitySnapshot(sessionId, snapshotData)); 137 } 138 139 /** 140 * Called by {@link ContentCaptureServerSession} to request removal of content capture data. 141 */ onDataRemovalRequest(@onNull DataRemovalRequest request)142 public void onDataRemovalRequest(@NonNull DataRemovalRequest request) { 143 scheduleAsyncRequest((s) -> s.onDataRemovalRequest(request)); 144 writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_USER_DATA_REMOVED, 145 mComponentName); 146 } 147 148 /** 149 * Called by {@link ContentCaptureServerSession} to notify a high-level activity event. 150 */ onActivityLifecycleEvent(@onNull ActivityEvent event)151 public void onActivityLifecycleEvent(@NonNull ActivityEvent event) { 152 scheduleAsyncRequest((s) -> s.onActivityEvent(event)); 153 } 154 155 public interface ContentCaptureServiceCallbacks 156 extends VultureCallback<RemoteContentCaptureService> { 157 // NOTE: so far we don't need to notify the callback implementation 158 // (ContentCaptureServerSession) of the request results (success, timeouts, etc..), so this 159 // callback interface is empty. 160 } 161 } 162