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