• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 
17 package com.android.server.appsearch;
18 
19 import static com.android.server.appsearch.indexer.IndexerMaintenanceConfig.APPS_INDEXER;
20 import static com.android.server.appsearch.indexer.IndexerMaintenanceConfig.APP_OPEN_EVENT_INDEXER;
21 import static com.android.server.appsearch.indexer.IndexerMaintenanceConfig.CONTACTS_INDEXER;
22 
23 import android.annotation.BinderThread;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.app.appsearch.util.ExceptionUtil;
27 import android.app.appsearch.util.LogUtil;
28 import android.content.Context;
29 import android.os.UserHandle;
30 import android.util.Log;
31 
32 import com.android.appsearch.flags.Flags;
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.server.SystemService;
35 import com.android.server.appsearch.appsindexer.AppOpenEventIndexerConfig;
36 import com.android.server.appsearch.appsindexer.AppOpenEventIndexerManagerService;
37 import com.android.server.appsearch.appsindexer.AppsIndexerConfig;
38 import com.android.server.appsearch.appsindexer.AppsIndexerManagerService;
39 import com.android.server.appsearch.appsindexer.FrameworkAppOpenEventIndexerConfig;
40 import com.android.server.appsearch.appsindexer.FrameworkAppsIndexerConfig;
41 import com.android.server.appsearch.contactsindexer.ContactsIndexerConfig;
42 import com.android.server.appsearch.contactsindexer.ContactsIndexerManagerService;
43 import com.android.server.appsearch.contactsindexer.FrameworkContactsIndexerConfig;
44 import com.android.server.appsearch.indexer.IndexerMaintenanceService;
45 
46 import java.io.PrintWriter;
47 import java.util.Objects;
48 
49 /** This class encapsulate the lifecycle methods of AppSearch module. */
50 public class AppSearchModule {
51     private static final String TAG = "AppSearchModule";
52 
53     /** Lifecycle definition for AppSearch module. */
54     public static class Lifecycle extends SystemService {
55         private AppSearchManagerService mAppSearchManagerService;
56         @VisibleForTesting @Nullable ContactsIndexerManagerService mContactsIndexerManagerService;
57 
58         @VisibleForTesting @Nullable AppsIndexerManagerService mAppsIndexerManagerService;
59 
60         @VisibleForTesting @Nullable
61         AppOpenEventIndexerManagerService mAppOpenEventIndexerManagerService;
62 
Lifecycle(Context context)63         public Lifecycle(Context context) {
64             super(context);
65         }
66 
67         /** Added primarily for testing purposes. */
68         @VisibleForTesting
69         @NonNull
createAppSearchManagerService( @onNull Context context, @NonNull AppSearchModule.Lifecycle lifecycle)70         AppSearchManagerService createAppSearchManagerService(
71                 @NonNull Context context, @NonNull AppSearchModule.Lifecycle lifecycle) {
72             Objects.requireNonNull(context);
73             Objects.requireNonNull(lifecycle);
74             return new AppSearchManagerService(context, lifecycle);
75         }
76 
77         /** Added primarily for testing purposes. */
78         @VisibleForTesting
79         @NonNull
createAppsIndexerManagerService( @onNull Context context, @NonNull AppsIndexerConfig config)80         AppsIndexerManagerService createAppsIndexerManagerService(
81                 @NonNull Context context, @NonNull AppsIndexerConfig config) {
82             Objects.requireNonNull(context);
83             Objects.requireNonNull(config);
84             return new AppsIndexerManagerService(context, config);
85         }
86 
87         /** Added primarily for testing purposes. */
88         @VisibleForTesting
89         @NonNull
createContactsIndexerManagerService( @onNull Context context, @NonNull ContactsIndexerConfig config)90         ContactsIndexerManagerService createContactsIndexerManagerService(
91                 @NonNull Context context, @NonNull ContactsIndexerConfig config) {
92             Objects.requireNonNull(context);
93             Objects.requireNonNull(config);
94             return new ContactsIndexerManagerService(context, config);
95         }
96 
97         /** Added primarily for testing purposes. */
98         @VisibleForTesting
99         @NonNull
createAppOpenEventIndexerManagerService( @onNull Context context, @NonNull AppOpenEventIndexerConfig config)100         AppOpenEventIndexerManagerService createAppOpenEventIndexerManagerService(
101                 @NonNull Context context, @NonNull AppOpenEventIndexerConfig config) {
102             Objects.requireNonNull(context);
103             Objects.requireNonNull(config);
104             return new AppOpenEventIndexerManagerService(context, config);
105         }
106 
107         @Override
onStart()108         public void onStart() {
109             mAppSearchManagerService =
110                     createAppSearchManagerService(getContext(), /* lifecycle= */ this);
111 
112             try {
113                 mAppSearchManagerService.onStart();
114             } catch (RuntimeException e) {
115                 Log.e(TAG, "Failed to start AppSearch service", e);
116                 // If AppSearch service fails to start, skip starting ContactsIndexer service
117                 // since it indexes CP2 contacts into AppSearch builtin:Person corpus
118                 ExceptionUtil.handleException(e);
119                 return;
120             }
121 
122             // It is safe to check DeviceConfig here, since SettingsProvider, which DeviceConfig
123             // uses, starts before AppSearch.
124             ContactsIndexerConfig contactsIndexerConfig = new FrameworkContactsIndexerConfig();
125             if (contactsIndexerConfig.isContactsIndexerEnabled()) {
126 
127                 mContactsIndexerManagerService =
128                         createContactsIndexerManagerService(getContext(), contactsIndexerConfig);
129                 try {
130                     mContactsIndexerManagerService.onStart();
131                 } catch (Throwable t) {
132                     Log.e(TAG, "Failed to start ContactsIndexer service", t);
133                     // Release the Contacts Indexer instance as it won't be started until the next
134                     // system_server restart on a device reboot.
135                     mContactsIndexerManagerService = null;
136                 }
137             } else if (LogUtil.INFO) {
138                 Log.i(TAG, "ContactsIndexer service is disabled.");
139             }
140 
141             AppsIndexerConfig appsIndexerConfig = new FrameworkAppsIndexerConfig();
142             // Flags.appsIndexerEnabled will be rolled out through gantry, and this check will be
143             // removed once it is fully rolled out. appsIndexerConfig.isAppsIndexerEnabled checks
144             // DeviceConfig, so we can keep this check here in case we need to turn off apps
145             // indexer.
146             if (Flags.appsIndexerEnabled() && appsIndexerConfig.isAppsIndexerEnabled()) {
147                 mAppsIndexerManagerService =
148                         createAppsIndexerManagerService(getContext(), appsIndexerConfig);
149                 try {
150                     mAppsIndexerManagerService.onStart();
151                 } catch (Throwable t) {
152                     Log.e(TAG, "Failed to start AppsIndexer service", t);
153                     mAppsIndexerManagerService = null;
154                 }
155             } else if (LogUtil.INFO) {
156                 Log.i(TAG, "AppsIndexer service is disabled.");
157             }
158 
159             AppOpenEventIndexerConfig appOpenEventIndexerConfig =
160                     new FrameworkAppOpenEventIndexerConfig();
161             // Flags.appOpenEventIndexerEnabled will be rolled out through gantry, and this check
162             // will be removed once it is fully rolled out.
163             // appOpenEventIndexerConfig.isAppOpenEventIndexerEnabled checks DeviceConfig, so we can
164             // keep this check here in case we need to turn off app open event indexer.
165             if (Flags.appOpenEventIndexerEnabled()
166                     && appOpenEventIndexerConfig.isAppOpenEventIndexerEnabled()) {
167                 mAppOpenEventIndexerManagerService =
168                         createAppOpenEventIndexerManagerService(
169                                 getContext(), appOpenEventIndexerConfig);
170                 try {
171                     mAppOpenEventIndexerManagerService.onStart();
172                 } catch (Throwable t) {
173                     Log.e(TAG, "Failed to start app open event indexer service", t);
174                     mAppOpenEventIndexerManagerService = null;
175                 }
176             } else if (LogUtil.INFO) {
177                 Log.i(TAG, "AppOpenEventIndexer service is disabled.");
178             }
179         }
180 
181         /** Dumps ContactsIndexer internal state for the user. */
182         @BinderThread
dumpContactsIndexerForUser( @onNull UserHandle userHandle, @NonNull PrintWriter pw, boolean verbose)183         void dumpContactsIndexerForUser(
184                 @NonNull UserHandle userHandle, @NonNull PrintWriter pw, boolean verbose) {
185             if (mContactsIndexerManagerService != null) {
186                 mContactsIndexerManagerService.dumpContactsIndexerForUser(userHandle, pw, verbose);
187             } else {
188                 pw.println("No dumpsys for ContactsIndexer as it is disabled.");
189             }
190         }
191 
192         @BinderThread
dumpAppsIndexerForUser(@onNull UserHandle userHandle, @NonNull PrintWriter pw)193         void dumpAppsIndexerForUser(@NonNull UserHandle userHandle, @NonNull PrintWriter pw) {
194             if (mAppsIndexerManagerService != null) {
195                 mAppsIndexerManagerService.dumpAppsIndexerForUser(userHandle, pw);
196             } else {
197                 pw.println("No dumpsys for AppsIndexer as it is disabled");
198             }
199         }
200 
201         @BinderThread
dumpAppOpenEventIndexerForUser( @onNull UserHandle userHandle, @NonNull PrintWriter pw)202         void dumpAppOpenEventIndexerForUser(
203                 @NonNull UserHandle userHandle, @NonNull PrintWriter pw) {
204             if (mAppOpenEventIndexerManagerService != null) {
205                 mAppOpenEventIndexerManagerService.dumpAppOpenEventIndexerForUser(userHandle, pw);
206             } else {
207                 pw.println("No dumpsys for AppOpenEventIndexer as it is disabled");
208             }
209         }
210 
211         @Override
onBootPhase(int phase)212         public void onBootPhase(int phase) {
213             mAppSearchManagerService.onBootPhase(phase);
214         }
215 
216         @Override
onUserUnlocking(@onNull TargetUser user)217         public void onUserUnlocking(@NonNull TargetUser user) {
218             mAppSearchManagerService.onUserUnlocking(user);
219             if (mContactsIndexerManagerService == null) {
220                 IndexerMaintenanceService.cancelUpdateJobIfScheduled(
221                         getContext(), user.getUserHandle(), CONTACTS_INDEXER);
222             } else {
223                 mContactsIndexerManagerService.onUserUnlocking(user);
224             }
225 
226             if (mAppsIndexerManagerService == null) {
227                 IndexerMaintenanceService.cancelUpdateJobIfScheduled(
228                         getContext(), user.getUserHandle(), APPS_INDEXER);
229             } else {
230                 mAppsIndexerManagerService.onUserUnlocking(user);
231             }
232 
233             if (mAppOpenEventIndexerManagerService == null) {
234                 IndexerMaintenanceService.cancelUpdateJobIfScheduled(
235                         getContext(), user.getUserHandle(), APP_OPEN_EVENT_INDEXER);
236             } else {
237                 // App Open Event Indexer only schedules a periodic update job on user unlock and
238                 // does not run an update
239                 mAppOpenEventIndexerManagerService.onUserUnlocking(user);
240             }
241         }
242 
243         @Override
onUserStopping(@onNull TargetUser user)244         public void onUserStopping(@NonNull TargetUser user) {
245             mAppSearchManagerService.onUserStopping(user);
246             if (mContactsIndexerManagerService != null) {
247                 mContactsIndexerManagerService.onUserStopping(user);
248             }
249             if (mAppsIndexerManagerService != null) {
250                 mAppsIndexerManagerService.onUserStopping(user);
251             }
252             if (mAppOpenEventIndexerManagerService != null) {
253                 mAppOpenEventIndexerManagerService.onUserStopping(user);
254             }
255         }
256     }
257 }
258