• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ISerialManager;
22 import android.hardware.SerialManager;
23 import android.os.Handler;
24 import android.os.HandlerThread;
25 import android.os.Looper;
26 import android.os.PermissionEnforcer;
27 import android.os.ServiceManager;
28 import android.os.UserHandle;
29 import android.ravenwood.example.BlueManager;
30 import android.ravenwood.example.RedManager;
31 import android.util.ArrayMap;
32 import android.util.Singleton;
33 
34 import java.util.Objects;
35 import java.util.concurrent.Executor;
36 import java.util.function.Supplier;
37 
38 public class RavenwoodContext extends RavenwoodBaseContext {
39     private final String mPackageName;
40     private final HandlerThread mMainThread;
41 
42     private final RavenwoodPermissionEnforcer mEnforcer = new RavenwoodPermissionEnforcer();
43 
44     private final ArrayMap<Class<?>, String> mClassToName = new ArrayMap<>();
45     private final ArrayMap<String, Supplier<?>> mNameToFactory = new ArrayMap<>();
46 
registerService(Class<?> serviceClass, String serviceName, Supplier<?> serviceSupplier)47     private void registerService(Class<?> serviceClass, String serviceName,
48             Supplier<?> serviceSupplier) {
49         mClassToName.put(serviceClass, serviceName);
50         mNameToFactory.put(serviceName, serviceSupplier);
51     }
52 
RavenwoodContext(String packageName, HandlerThread mainThread)53     public RavenwoodContext(String packageName, HandlerThread mainThread) {
54         mPackageName = packageName;
55         mMainThread = mainThread;
56 
57         // Services provided by a typical shipping device
58         registerService(ClipboardManager.class,
59                 Context.CLIPBOARD_SERVICE, memoize(() ->
60                         new ClipboardManager(this, getMainThreadHandler())));
61         registerService(PermissionEnforcer.class,
62                 Context.PERMISSION_ENFORCER_SERVICE, () -> mEnforcer);
63         registerService(SerialManager.class,
64                 Context.SERIAL_SERVICE, memoize(() ->
65                         new SerialManager(this, ISerialManager.Stub.asInterface(
66                                 ServiceManager.getService(Context.SERIAL_SERVICE)))
67                 ));
68 
69         // Additional services we provide for testing purposes
70         registerService(BlueManager.class,
71                 BlueManager.SERVICE_NAME, memoize(() -> new BlueManager()));
72         registerService(RedManager.class,
73                 RedManager.SERVICE_NAME, memoize(() -> new RedManager()));
74     }
75 
76     @Override
getSystemService(String serviceName)77     public Object getSystemService(String serviceName) {
78         // TODO: pivot to using SystemServiceRegistry
79         final Supplier<?> serviceSupplier = mNameToFactory.get(serviceName);
80         if (serviceSupplier != null) {
81             return serviceSupplier.get();
82         } else {
83             throw new UnsupportedOperationException(
84                     "Service " + serviceName + " not yet supported under Ravenwood");
85         }
86     }
87 
88     @Override
getSystemServiceName(Class<?> serviceClass)89     public String getSystemServiceName(Class<?> serviceClass) {
90         // TODO: pivot to using SystemServiceRegistry
91         final String serviceName = mClassToName.get(serviceClass);
92         if (serviceName != null) {
93             return serviceName;
94         } else {
95             throw new UnsupportedOperationException(
96                     "Service " + serviceClass + " not yet supported under Ravenwood");
97         }
98     }
99 
100     @Override
getMainLooper()101     public Looper getMainLooper() {
102         Objects.requireNonNull(mMainThread,
103                 "Test must request setProvideMainThread() via RavenwoodRule");
104         return mMainThread.getLooper();
105     }
106 
107     @Override
getMainThreadHandler()108     public Handler getMainThreadHandler() {
109         Objects.requireNonNull(mMainThread,
110                 "Test must request setProvideMainThread() via RavenwoodRule");
111         return mMainThread.getThreadHandler();
112     }
113 
114     @Override
getMainExecutor()115     public Executor getMainExecutor() {
116         Objects.requireNonNull(mMainThread,
117                 "Test must request setProvideMainThread() via RavenwoodRule");
118         return mMainThread.getThreadExecutor();
119     }
120 
121     @Override
getPackageName()122     public String getPackageName() {
123         return Objects.requireNonNull(mPackageName,
124                 "Test must request setPackageName() via RavenwoodRule");
125     }
126 
127     @Override
getOpPackageName()128     public String getOpPackageName() {
129         return Objects.requireNonNull(mPackageName,
130                 "Test must request setPackageName() via RavenwoodRule");
131     }
132 
133     @Override
getAttributionTag()134     public String getAttributionTag() {
135         return null;
136     }
137 
138     @Override
getUser()139     public UserHandle getUser() {
140         return android.os.UserHandle.of(android.os.UserHandle.myUserId());
141     }
142 
143     @Override
getUserId()144     public int getUserId() {
145         return android.os.UserHandle.myUserId();
146     }
147 
148     @Override
getDeviceId()149     public int getDeviceId() {
150         return Context.DEVICE_ID_DEFAULT;
151     }
152 
153     /**
154      * Wrap the given {@link Supplier} to become memoized.
155      *
156      * The underlying {@link Supplier} will only be invoked once, and that result will be cached
157      * and returned for any future requests.
158      */
memoize(ThrowingSupplier<T> supplier)159     private static <T> Supplier<T> memoize(ThrowingSupplier<T> supplier) {
160         final Singleton<T> singleton = new Singleton<>() {
161             @Override
162             protected T create() {
163                 try {
164                     return supplier.get();
165                 } catch (Exception e) {
166                     throw new RuntimeException(e);
167                 }
168             }
169         };
170         return () -> {
171             return singleton.get();
172         };
173     }
174 
175     public interface ThrowingSupplier<T> {
get()176         T get() throws Exception;
177     }
178 }
179