1 /* 2 * Copyright (C) 2024 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 android.platform.test.ravenwood; 18 19 import android.content.ClipboardManager; 20 import android.content.Context; 21 import android.hardware.SerialManager; 22 import android.os.ServiceManager; 23 import android.os.SystemClock; 24 import android.ravenwood.example.BlueManager; 25 import android.ravenwood.example.RedManager; 26 import android.util.ArrayMap; 27 import android.util.ArraySet; 28 29 import com.android.server.LocalServices; 30 import com.android.server.SystemService; 31 import com.android.server.SystemServiceManager; 32 import com.android.server.compat.PlatformCompat; 33 import com.android.server.compat.PlatformCompatNative; 34 import com.android.server.utils.TimingsTraceAndSlog; 35 36 import java.util.Collection; 37 import java.util.Set; 38 39 public class RavenwoodSystemServer { 40 41 static final String ANDROID_PACKAGE_NAME = "android"; 42 43 /** 44 * Set of services that we know how to provide under Ravenwood. We keep this set distinct 45 * from {@code com.android.server.SystemServer} to give us the ability to choose either 46 * "real" or "fake" implementations based on the commitments of the service owner. 47 * 48 * Map from {@code FooManager.class} to the {@code com.android.server.SystemService} 49 * lifecycle class name used to instantiate and drive that service. 50 */ 51 private static final ArrayMap<Class<?>, String> sKnownServices = new ArrayMap<>(); 52 53 static { 54 // Services provided by a typical shipping device sKnownServices.put(ClipboardManager.class, "com.android.server.FakeClipboardService$Lifecycle")55 sKnownServices.put(ClipboardManager.class, 56 "com.android.server.FakeClipboardService$Lifecycle"); sKnownServices.put(SerialManager.class, "com.android.server.SerialService$Lifecycle")57 sKnownServices.put(SerialManager.class, 58 "com.android.server.SerialService$Lifecycle"); 59 60 // Additional services we provide for testing purposes sKnownServices.put(BlueManager.class, "com.android.server.example.BlueManagerService$Lifecycle")61 sKnownServices.put(BlueManager.class, 62 "com.android.server.example.BlueManagerService$Lifecycle"); sKnownServices.put(RedManager.class, "com.android.server.example.RedManagerService$Lifecycle")63 sKnownServices.put(RedManager.class, 64 "com.android.server.example.RedManagerService$Lifecycle"); 65 } 66 67 private static Set<Class<?>> sStartedServices; 68 private static TimingsTraceAndSlog sTimings; 69 private static SystemServiceManager sServiceManager; 70 init(Context systemServerContext)71 public static void init(Context systemServerContext) { 72 // Always start PlatformCompat, regardless of the requested services. 73 // PlatformCompat is not really a SystemService, so it won't receive boot phases / etc. 74 // This initialization code is copied from SystemServer.java. 75 PlatformCompat platformCompat = new PlatformCompat(systemServerContext); 76 ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, platformCompat); 77 ServiceManager.addService(Context.PLATFORM_COMPAT_NATIVE_SERVICE, 78 new PlatformCompatNative(platformCompat)); 79 80 sStartedServices = new ArraySet<>(); 81 sTimings = new TimingsTraceAndSlog(); 82 sServiceManager = new SystemServiceManager(systemServerContext); 83 sServiceManager.setStartInfo(false, 84 SystemClock.elapsedRealtime(), 85 SystemClock.uptimeMillis()); 86 LocalServices.addService(SystemServiceManager.class, sServiceManager); 87 88 startServices(sKnownServices.keySet()); 89 sServiceManager.sealStartedServices(); 90 91 // TODO: expand to include additional boot phases when relevant 92 sServiceManager.startBootPhase(sTimings, SystemService.PHASE_SYSTEM_SERVICES_READY); 93 sServiceManager.startBootPhase(sTimings, SystemService.PHASE_BOOT_COMPLETED); 94 } 95 reset()96 public static void reset() { 97 // TODO: consider introducing shutdown boot phases 98 99 LocalServices.removeServiceForTest(SystemServiceManager.class); 100 sServiceManager = null; 101 sTimings = null; 102 sStartedServices = null; 103 } 104 startServices(Collection<Class<?>> serviceClasses)105 private static void startServices(Collection<Class<?>> serviceClasses) { 106 for (Class<?> serviceClass : serviceClasses) { 107 // Quietly ignore duplicate requests if service already started 108 if (sStartedServices.contains(serviceClass)) continue; 109 sStartedServices.add(serviceClass); 110 111 final String serviceName = sKnownServices.get(serviceClass); 112 if (serviceName == null) { 113 throw new RuntimeException("The requested service " + serviceClass 114 + " is not yet supported under the Ravenwood deviceless testing " 115 + "environment; consider requesting support from the API owner or " 116 + "consider using Mockito; more details at go/ravenwood-docs"); 117 } 118 119 // Start service and then depth-first traversal of any dependencies 120 final SystemService instance = sServiceManager.startService(serviceName); 121 startServices(instance.getDependencies()); 122 } 123 } 124 } 125