1 /* 2 * Copyright (C) 2021 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.nearby.common.servicemonitor; 18 19 import android.annotation.Nullable; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.os.Handler; 23 import android.os.IBinder; 24 import android.os.RemoteException; 25 26 import java.io.PrintWriter; 27 import java.util.Objects; 28 import java.util.concurrent.Executor; 29 30 /** 31 * This is exported from frameworks ServiceWatcher. 32 * A ServiceMonitor is responsible for continuously maintaining an active binding to a service 33 * selected by it's {@link ServiceProvider}. The {@link ServiceProvider} may change the service it 34 * selects over time, and the currently bound service may crash, restart, have a user change, have 35 * changes made to its package, and so on and so forth. The ServiceMonitor is responsible for 36 * maintaining the binding across all these changes. 37 * 38 * <p>Clients may invoke {@link BinderOperation}s on the ServiceMonitor, and it will make a best 39 * effort to run these on the currently bound service, but individual operations may fail (if there 40 * is no service currently bound for instance). In order to help clients maintain the correct state, 41 * clients may supply a {@link ServiceListener}, which is informed when the ServiceMonitor connects 42 * and disconnects from a service. This allows clients to bring a bound service back into a known 43 * state on connection, and then run binder operations from there. In order to help clients 44 * accomplish this, ServiceMonitor guarantees that {@link BinderOperation}s and the 45 * {@link ServiceListener} will always be run on the same thread, so that strong ordering guarantees 46 * can be established between them. 47 * 48 * There is never any guarantee of whether a ServiceMonitor is currently connected to a service, and 49 * whether any particular {@link BinderOperation} will succeed. Clients must ensure they do not rely 50 * on this, and instead use {@link ServiceListener} notifications as necessary to recover from 51 * failures. 52 */ 53 public interface ServiceMonitor { 54 55 /** 56 * Operation to run on a binder interface. All operations will be run on the thread used by the 57 * ServiceMonitor this is run with. 58 */ 59 interface BinderOperation { 60 /** Invoked to run the operation. Run on the ServiceMonitor thread. */ run(IBinder binder)61 void run(IBinder binder) throws RemoteException; 62 63 /** 64 * Invoked if {@link #run(IBinder)} could not be invoked because there was no current 65 * binding, or if {@link #run(IBinder)} threw an exception ({@link RemoteException} or 66 * {@link RuntimeException}). This callback is only intended for resource deallocation and 67 * cleanup in response to a single binder operation, it should not be used to propagate 68 * errors further. Run on the ServiceMonitor thread. 69 */ onError()70 default void onError() {} 71 } 72 73 /** 74 * Listener for bind and unbind events. All operations will be run on the thread used by the 75 * ServiceMonitor this is run with. 76 * 77 * @param <TBoundServiceInfo> type of bound service 78 */ 79 interface ServiceListener<TBoundServiceInfo extends BoundServiceInfo> { 80 /** Invoked when a service is bound. Run on the ServiceMonitor thread. */ onBind(IBinder binder, TBoundServiceInfo service)81 void onBind(IBinder binder, TBoundServiceInfo service) throws RemoteException; 82 83 /** Invoked when a service is unbound. Run on the ServiceMonitor thread. */ onUnbind()84 void onUnbind(); 85 } 86 87 /** 88 * A listener for when a {@link ServiceProvider} decides that the current service has changed. 89 */ 90 interface ServiceChangedListener { 91 /** 92 * Should be invoked when the current service may have changed. 93 */ onServiceChanged()94 void onServiceChanged(); 95 } 96 97 /** 98 * This provider encapsulates the logic of deciding what service a {@link ServiceMonitor} should 99 * be bound to at any given moment. 100 * 101 * @param <TBoundServiceInfo> type of bound service 102 */ 103 interface ServiceProvider<TBoundServiceInfo extends BoundServiceInfo> { 104 /** 105 * Should return true if there exists at least one service capable of meeting the criteria 106 * of this provider. This does not imply that {@link #getServiceInfo()} will always return a 107 * non-null result, as any service may be disqualified for various reasons at any point in 108 * time. May be invoked at any time from any thread and thus should generally not have any 109 * dependency on the other methods in this interface. 110 */ hasMatchingService()111 boolean hasMatchingService(); 112 113 /** 114 * Invoked when the provider should start monitoring for any changes that could result in a 115 * different service selection, and should invoke 116 * {@link ServiceChangedListener#onServiceChanged()} in that case. {@link #getServiceInfo()} 117 * may be invoked after this method is called. 118 */ register(ServiceChangedListener listener)119 void register(ServiceChangedListener listener); 120 121 /** 122 * Invoked when the provider should stop monitoring for any changes that could result in a 123 * different service selection, should no longer invoke 124 * {@link ServiceChangedListener#onServiceChanged()}. {@link #getServiceInfo()} will not be 125 * invoked after this method is called. 126 */ unregister()127 void unregister(); 128 129 /** 130 * Must be implemented to return the current service selected by this provider. May return 131 * null if no service currently meets the criteria. Only invoked while registered. 132 */ getServiceInfo()133 @Nullable TBoundServiceInfo getServiceInfo(); 134 } 135 136 /** 137 * Information on the service selected as the best option for binding. 138 */ 139 class BoundServiceInfo { 140 141 protected final @Nullable String mAction; 142 protected final int mUid; 143 protected final ComponentName mComponentName; 144 BoundServiceInfo(String action, int uid, ComponentName componentName)145 protected BoundServiceInfo(String action, int uid, ComponentName componentName) { 146 mAction = action; 147 mUid = uid; 148 mComponentName = Objects.requireNonNull(componentName); 149 } 150 151 /** Returns the action associated with this bound service. */ getAction()152 public @Nullable String getAction() { 153 return mAction; 154 } 155 156 /** Returns the component of this bound service. */ getComponentName()157 public ComponentName getComponentName() { 158 return mComponentName; 159 } 160 161 @Override equals(Object o)162 public final boolean equals(Object o) { 163 if (this == o) { 164 return true; 165 } 166 if (!(o instanceof BoundServiceInfo)) { 167 return false; 168 } 169 170 BoundServiceInfo that = (BoundServiceInfo) o; 171 return mUid == that.mUid 172 && Objects.equals(mAction, that.mAction) 173 && mComponentName.equals(that.mComponentName); 174 } 175 176 @Override hashCode()177 public final int hashCode() { 178 return Objects.hash(mAction, mUid, mComponentName); 179 } 180 181 @Override toString()182 public String toString() { 183 if (mComponentName == null) { 184 return "none"; 185 } else { 186 return mUid + "/" + mComponentName.flattenToShortString(); 187 } 188 } 189 } 190 191 /** 192 * Creates a new ServiceMonitor instance. 193 */ create( Context context, String tag, ServiceProvider<TBoundServiceInfo> serviceProvider, @Nullable ServiceListener<? super TBoundServiceInfo> serviceListener)194 static <TBoundServiceInfo extends BoundServiceInfo> ServiceMonitor create( 195 Context context, 196 String tag, 197 ServiceProvider<TBoundServiceInfo> serviceProvider, 198 @Nullable ServiceListener<? super TBoundServiceInfo> serviceListener) { 199 return create(context, ForegroundThread.getHandler(), ForegroundThread.getExecutor(), tag, 200 serviceProvider, serviceListener); 201 } 202 203 /** 204 * Creates a new ServiceMonitor instance that runs on the given handler. 205 */ create( Context context, Handler handler, Executor executor, String tag, ServiceProvider<TBoundServiceInfo> serviceProvider, @Nullable ServiceListener<? super TBoundServiceInfo> serviceListener)206 static <TBoundServiceInfo extends BoundServiceInfo> ServiceMonitor create( 207 Context context, 208 Handler handler, 209 Executor executor, 210 String tag, 211 ServiceProvider<TBoundServiceInfo> serviceProvider, 212 @Nullable ServiceListener<? super TBoundServiceInfo> serviceListener) { 213 return new ServiceMonitorImpl<>(context, handler, executor, tag, serviceProvider, 214 serviceListener); 215 } 216 217 /** 218 * Returns true if there is at least one service that the ServiceMonitor could hypothetically 219 * bind to, as selected by the {@link ServiceProvider}. 220 */ checkServiceResolves()221 boolean checkServiceResolves(); 222 223 /** 224 * Registers the ServiceMonitor, so that it will begin maintaining an active binding to the 225 * service selected by {@link ServiceProvider}, until {@link #unregister()} is called. 226 */ register()227 void register(); 228 229 /** 230 * Unregisters the ServiceMonitor, so that it will release any active bindings. If the 231 * ServiceMonitor is currently bound, this will result in one final 232 * {@link ServiceListener#onUnbind()} invocation, which may happen after this method completes 233 * (but which is guaranteed to occur before any further 234 * {@link ServiceListener#onBind(IBinder, BoundServiceInfo)} invocation in response to a later 235 * call to {@link #register()}). 236 */ unregister()237 void unregister(); 238 239 /** 240 * Runs the given binder operation on the currently bound service (if available). The operation 241 * will always fail if the ServiceMonitor is not currently registered. 242 */ runOnBinder(BinderOperation operation)243 void runOnBinder(BinderOperation operation); 244 245 /** 246 * Dumps ServiceMonitor information. 247 */ dump(PrintWriter pw)248 void dump(PrintWriter pw); 249 } 250