1 /* 2 * Copyright (C) 2020 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.timezonedetector.location; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.Context; 22 import android.os.Handler; 23 import android.os.RemoteCallback; 24 import android.util.IndentingPrintWriter; 25 26 import com.android.internal.annotations.GuardedBy; 27 import com.android.server.timezonedetector.Dumpable; 28 29 import java.util.Objects; 30 31 /** 32 * System server-side proxy for ITimeZoneProvider implementations, i.e. this provides the system 33 * server object used to communicate with a remote TimeZoneProvider over Binder, which could be 34 * running in a different process. As TimeZoneProviders are bound / unbound this proxy will rebind 35 * to the "best" available remote process. 36 * 37 * <p>Threading guarantees provided / required by this interface: 38 * <ul> 39 * <li>All public methods defined by this class must be invoked using the {@link Handler} thread 40 * from the {@link ThreadingDomain} passed to the constructor, excluding 41 * {@link #dump(IndentingPrintWriter, String[])}</li> 42 * <li>Non-static public methods that make binder calls to remote processes (e.g. 43 * {@link #setRequest(TimeZoneProviderRequest)}) are executed asynchronously and will return 44 * immediately.</li> 45 * <li>Callbacks received via binder are delivered via {@link Listener} are delivered on the 46 * {@link Handler} thread from the {@link ThreadingDomain} passed to the constructor. 47 * </ul> 48 * 49 * <p>This class exists to enable the introduction of test implementations of {@link 50 * LocationTimeZoneProviderProxy} that can be used when a device is in a test mode to inject test 51 * events / behavior that are otherwise difficult to simulate. 52 */ 53 abstract class LocationTimeZoneProviderProxy implements Dumpable { 54 55 @NonNull protected final Context mContext; 56 @NonNull protected final ThreadingDomain mThreadingDomain; 57 @NonNull protected final Object mSharedLock; 58 59 // Non-null and effectively final after setListener() is called. 60 @GuardedBy("mSharedLock") 61 @Nullable 62 protected Listener mListener; 63 LocationTimeZoneProviderProxy( @onNull Context context, @NonNull ThreadingDomain threadingDomain)64 LocationTimeZoneProviderProxy( 65 @NonNull Context context, @NonNull ThreadingDomain threadingDomain) { 66 mContext = Objects.requireNonNull(context); 67 mThreadingDomain = Objects.requireNonNull(threadingDomain); 68 mSharedLock = threadingDomain.getLockObject(); 69 } 70 71 /** 72 * Initializes the proxy. The supplied listener can expect to receive all events after this 73 * point. This method calls {@link #onInitialize()} for subclasses to handle their own 74 * initialization. 75 */ initialize(@onNull Listener listener)76 void initialize(@NonNull Listener listener) { 77 Objects.requireNonNull(listener); 78 synchronized (mSharedLock) { 79 if (mListener != null) { 80 throw new IllegalStateException("listener already set"); 81 } 82 this.mListener = listener; 83 onInitialize(); 84 } 85 } 86 87 /** 88 * Implemented by subclasses to initializes the proxy. This is called after {@link #mListener} 89 * is set. 90 */ 91 @GuardedBy("mSharedLock") onInitialize()92 abstract void onInitialize(); 93 94 /** 95 * Destroys the proxy. This method calls {@link #onDestroy()} for subclasses to handle their own 96 * destruction. 97 */ destroy()98 void destroy() { 99 synchronized (mSharedLock) { 100 onDestroy(); 101 } 102 } 103 104 /** 105 * Implemented by subclasses to destroy the proxy. 106 */ 107 @GuardedBy("mSharedLock") onDestroy()108 abstract void onDestroy(); 109 110 /** 111 * Sets a new request for the provider. 112 */ setRequest(@onNull TimeZoneProviderRequest request)113 abstract void setRequest(@NonNull TimeZoneProviderRequest request); 114 115 /** 116 * Processes the supplied test command. An optional callback can be supplied to listen for a 117 * response. 118 */ handleTestCommand(@onNull TestCommand testCommand, @Nullable RemoteCallback callback)119 abstract void handleTestCommand(@NonNull TestCommand testCommand, 120 @Nullable RemoteCallback callback); 121 122 /** 123 * Handles a {@link TimeZoneProviderEvent} from a remote process. 124 */ handleTimeZoneProviderEvent(@onNull TimeZoneProviderEvent timeZoneProviderEvent)125 final void handleTimeZoneProviderEvent(@NonNull TimeZoneProviderEvent timeZoneProviderEvent) { 126 // These calls are invoked on a binder thread. Move to the mThreadingDomain thread as 127 // required by the guarantees for this class. 128 mThreadingDomain.post(() -> mListener.onReportTimeZoneProviderEvent(timeZoneProviderEvent)); 129 } 130 131 /** 132 * Interface for listening to location time zone providers. See {@link 133 * LocationTimeZoneProviderProxy} for threading guarantees. 134 */ 135 interface Listener { 136 137 /** 138 * Called when a provider receives a {@link TimeZoneProviderEvent}. 139 */ onReportTimeZoneProviderEvent(@onNull TimeZoneProviderEvent timeZoneProviderEvent)140 void onReportTimeZoneProviderEvent(@NonNull TimeZoneProviderEvent timeZoneProviderEvent); 141 142 /** 143 * Called when a provider is (re)bound. 144 */ onProviderBound()145 void onProviderBound(); 146 147 /** Called when a provider is unbound. */ onProviderUnbound()148 void onProviderUnbound(); 149 } 150 } 151