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.CONTACTS_INDEXER;
21 
22 import android.annotation.BinderThread;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.app.appsearch.util.ExceptionUtil;
26 import android.app.appsearch.util.LogUtil;
27 import android.content.Context;
28 import android.os.UserHandle;
29 import android.util.Log;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 import com.android.server.SystemService;
33 import com.android.server.appsearch.appsindexer.AppsIndexerConfig;
34 import com.android.server.appsearch.appsindexer.AppsIndexerManagerService;
35 import com.android.server.appsearch.appsindexer.FrameworkAppsIndexerConfig;
36 import com.android.server.appsearch.contactsindexer.ContactsIndexerConfig;
37 import com.android.server.appsearch.contactsindexer.ContactsIndexerManagerService;
38 import com.android.server.appsearch.contactsindexer.FrameworkContactsIndexerConfig;
39 import com.android.server.appsearch.indexer.IndexerMaintenanceService;
40 
41 import java.io.PrintWriter;
42 import java.util.Objects;
43 
44 /** This class encapsulate the lifecycle methods of AppSearch module. */
45 public class AppSearchModule {
46     private static final String TAG = "AppSearchModule";
47 
48     /** Lifecycle definition for AppSearch module. */
49     public static class Lifecycle extends SystemService {
50         private AppSearchManagerService mAppSearchManagerService;
51         @VisibleForTesting @Nullable ContactsIndexerManagerService mContactsIndexerManagerService;
52 
53         @VisibleForTesting @Nullable AppsIndexerManagerService mAppsIndexerManagerService;
54 
Lifecycle(Context context)55         public Lifecycle(Context context) {
56             super(context);
57         }
58 
59         /** Added primarily for testing purposes. */
60         @VisibleForTesting
61         @NonNull
createAppSearchManagerService( @onNull Context context, @NonNull AppSearchModule.Lifecycle lifecycle)62         AppSearchManagerService createAppSearchManagerService(
63                 @NonNull Context context, @NonNull AppSearchModule.Lifecycle lifecycle) {
64             Objects.requireNonNull(context);
65             Objects.requireNonNull(lifecycle);
66             return new AppSearchManagerService(context, lifecycle);
67         }
68 
69         /** Added primarily for testing purposes. */
70         @VisibleForTesting
71         @NonNull
createAppsIndexerManagerService( @onNull Context context, @NonNull AppsIndexerConfig config)72         AppsIndexerManagerService createAppsIndexerManagerService(
73                 @NonNull Context context, @NonNull AppsIndexerConfig config) {
74             Objects.requireNonNull(context);
75             Objects.requireNonNull(config);
76             return new AppsIndexerManagerService(context, config);
77         }
78 
79         /** Added primarily for testing purposes. */
80         @VisibleForTesting
81         @NonNull
createContactsIndexerManagerService( @onNull Context context, @NonNull ContactsIndexerConfig config)82         ContactsIndexerManagerService createContactsIndexerManagerService(
83                 @NonNull Context context, @NonNull ContactsIndexerConfig config) {
84             Objects.requireNonNull(context);
85             Objects.requireNonNull(config);
86             return new ContactsIndexerManagerService(context, config);
87         }
88 
89         @Override
onStart()90         public void onStart() {
91             mAppSearchManagerService =
92                     createAppSearchManagerService(getContext(), /* lifecycle= */ this);
93 
94             try {
95                 mAppSearchManagerService.onStart();
96             } catch (RuntimeException e) {
97                 Log.e(TAG, "Failed to start AppSearch service", e);
98                 // If AppSearch service fails to start, skip starting ContactsIndexer service
99                 // since it indexes CP2 contacts into AppSearch builtin:Person corpus
100                 ExceptionUtil.handleException(e);
101                 return;
102             }
103 
104             // It is safe to check DeviceConfig here, since SettingsProvider, which DeviceConfig
105             // uses, starts before AppSearch.
106             ContactsIndexerConfig contactsIndexerConfig = new FrameworkContactsIndexerConfig();
107             if (contactsIndexerConfig.isContactsIndexerEnabled()) {
108 
109                 mContactsIndexerManagerService =
110                         createContactsIndexerManagerService(getContext(), contactsIndexerConfig);
111                 try {
112                     mContactsIndexerManagerService.onStart();
113                 } catch (Throwable t) {
114                     Log.e(TAG, "Failed to start ContactsIndexer service", t);
115                     // Release the Contacts Indexer instance as it won't be started until the next
116                     // system_server restart on a device reboot.
117                     mContactsIndexerManagerService = null;
118                 }
119             } else if (LogUtil.INFO) {
120                 Log.i(TAG, "ContactsIndexer service is disabled.");
121             }
122 
123             AppsIndexerConfig appsIndexerConfig = new FrameworkAppsIndexerConfig();
124             if (appsIndexerConfig.isAppsIndexerEnabled()) {
125                 mAppsIndexerManagerService =
126                         createAppsIndexerManagerService(getContext(), appsIndexerConfig);
127                 try {
128                     mAppsIndexerManagerService.onStart();
129                 } catch (Throwable t) {
130                     Log.e(TAG, "Failed to start AppsIndexer service", t);
131                     mAppsIndexerManagerService = null;
132                 }
133             } else if (LogUtil.INFO) {
134                 Log.i(TAG, "AppsIndexer service is disabled.");
135             }
136         }
137 
138         /** Dumps ContactsIndexer internal state for the user. */
139         @BinderThread
dumpContactsIndexerForUser( @onNull UserHandle userHandle, @NonNull PrintWriter pw, boolean verbose)140         void dumpContactsIndexerForUser(
141                 @NonNull UserHandle userHandle, @NonNull PrintWriter pw, boolean verbose) {
142             if (mContactsIndexerManagerService != null) {
143                 mContactsIndexerManagerService.dumpContactsIndexerForUser(userHandle, pw, verbose);
144             } else {
145                 pw.println("No dumpsys for ContactsIndexer as it is disabled.");
146             }
147         }
148 
149         @BinderThread
dumpAppsIndexerForUser(@onNull UserHandle userHandle, @NonNull PrintWriter pw)150         void dumpAppsIndexerForUser(@NonNull UserHandle userHandle, @NonNull PrintWriter pw) {
151             if (mAppsIndexerManagerService != null) {
152                 mAppsIndexerManagerService.dumpAppsIndexerForUser(userHandle, pw);
153             } else {
154                 pw.println("No dumpsys for AppsIndexer as it is disabled");
155             }
156         }
157 
158         @Override
onBootPhase(int phase)159         public void onBootPhase(int phase) {
160             mAppSearchManagerService.onBootPhase(phase);
161         }
162 
163         @Override
onUserUnlocking(@onNull TargetUser user)164         public void onUserUnlocking(@NonNull TargetUser user) {
165             mAppSearchManagerService.onUserUnlocking(user);
166             if (mContactsIndexerManagerService == null) {
167                 IndexerMaintenanceService.cancelUpdateJobIfScheduled(
168                         getContext(), user.getUserHandle(), CONTACTS_INDEXER);
169             } else {
170                 mContactsIndexerManagerService.onUserUnlocking(user);
171             }
172 
173             if (mAppsIndexerManagerService == null) {
174                 IndexerMaintenanceService.cancelUpdateJobIfScheduled(
175                         getContext(), user.getUserHandle(), APPS_INDEXER);
176             } else {
177                 mAppsIndexerManagerService.onUserUnlocking(user);
178             }
179         }
180 
181         @Override
onUserStopping(@onNull TargetUser user)182         public void onUserStopping(@NonNull TargetUser user) {
183             mAppSearchManagerService.onUserStopping(user);
184             if (mContactsIndexerManagerService != null) {
185                 mContactsIndexerManagerService.onUserStopping(user);
186             }
187             if (mAppsIndexerManagerService != null) {
188                 mAppsIndexerManagerService.onUserStopping(user);
189             }
190         }
191     }
192 }
193