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