Loading core/java/com/android/internal/listeners/ListenerExecutor.java 0 → 100644 +132 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.listeners; import android.annotation.Nullable; import java.util.concurrent.Executor; import java.util.function.Supplier; /** * Interface (trait) for executing listener style operations on an executor. */ public interface ListenerExecutor { /** * An listener operation to perform. * * @param <TListener> listener type */ interface ListenerOperation<TListener> { /** * Performs the operation on the given listener. */ void operate(TListener listener) throws Exception; /** * Called before this operation is to be run. Some operations may be canceled before they * are run, in which case this method may not be called. {@link #onPostExecute(boolean)} * will only be run if this method was run. */ default void onPreExecute() {} /** * Called if the operation fails while running. Will not be invoked in the event of a * RuntimeException, which will propagate normally. Implementations of * {@link ListenerExecutor} have the option to override * {@link ListenerExecutor#onOperationFailure(ListenerOperation, Exception)} instead to * intercept failures at the class level. */ default void onFailure(Exception e) { // implementations should handle any exceptions that may be thrown throw new AssertionError(e); } /** * Called after the operation is run. This method will always be called if * {@link #onPreExecute()} is called. Success implies that the operation was run to * completion with no failures. */ default void onPostExecute(boolean success) {} /** * Called after this operation is complete (which does not imply that it was necessarily * run). Will always be called once per operation, no matter if the operation was run or * not. Success implies that the operation was run to completion with no failures. */ default void onComplete(boolean success) {} } /** * May be override to handle operation failures at a class level. Will not be invoked in the * event of a RuntimeException, which will propagate normally. */ default <TListener> void onOperationFailure(ListenerOperation<TListener> operation, Exception exception) { operation.onFailure(exception); } /** * Executes the given listener operation on the given executor, using the provided listener * supplier. If the supplier returns a null value, or a value during the operation that does not * match the value prior to the operation, then the operation is considered canceled. */ default <TListener> void executeSafely(Executor executor, Supplier<TListener> listenerSupplier, @Nullable ListenerOperation<TListener> operation) { if (operation == null) { return; } boolean executing = false; boolean preexecute = false; try { TListener listener = listenerSupplier.get(); if (listener == null) { return; } operation.onPreExecute(); preexecute = true; executor.execute(() -> { boolean success = false; try { if (listener == listenerSupplier.get()) { operation.operate(listener); success = true; } } catch (Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } else { onOperationFailure(operation, e); } } finally { operation.onPostExecute(success); operation.onComplete(success); } }); executing = true; } finally { if (!executing) { if (preexecute) { operation.onPostExecute(false); } operation.onComplete(false); } } } } core/java/com/android/internal/listeners/ListenerTransport.java +0 −4 Original line number Original line Diff line number Diff line Loading @@ -45,10 +45,6 @@ public class ListenerTransport<TListener> { mListener = listener; mListener = listener; } } final boolean isRegistered() { return mListener != null; } /** /** * Prevents any listener invocations that happen-after this call. * Prevents any listener invocations that happen-after this call. */ */ Loading core/java/com/android/internal/listeners/ListenerTransportManager.javadeleted 100644 → 0 +0 −145 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.listeners; import android.annotation.NonNull; import android.os.RemoteException; import android.util.ArrayMap; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import java.util.Objects; /** * A listener manager which tracks listeners along with their keys. This class enforces proper use * of transport objects and ensure unregistration race conditions are handled properly. If listeners * should be multiplexed before being sent to the server, see {@link ListenerTransportMultiplexer} * instead. * * @param <TTransport> transport type */ public abstract class ListenerTransportManager<TTransport extends ListenerTransport<?>> { @GuardedBy("mTransports") private final ArrayMap<Object, TTransport> mTransports = new ArrayMap<>(); /** * Should be implemented to register the transport with the server. * * @see #reregisterWithServer(ListenerTransport, ListenerTransport) */ protected abstract void registerWithServer(TTransport transport) throws RemoteException; /** * Invoked when the server already has a transport registered for a key, and it is being * replaced with a new transport. The default implementation unregisters the old transport, then * registers the new transport, but this may be overridden by subclasses in order to reregister * more efficiently. */ protected void reregisterWithServer(TTransport oldTransport, TTransport newTransport) throws RemoteException { unregisterWithServer(oldTransport); registerWithServer(newTransport); } /** * Should be implemented to unregister the transport from the server. */ protected abstract void unregisterWithServer(TTransport transport) throws RemoteException; /** * Adds a new transport with the given key and makes a call to add the transport server side. If * a transport already exists with that key, it will be replaced by the new transport and * {@link #reregisterWithServer(ListenerTransport, ListenerTransport)} will be invoked to * replace the old transport with the new transport server side. If no transport exists with * that key, it will be added server side via {@link #registerWithServer(ListenerTransport)}. */ protected void registerListener(@NonNull Object key, @NonNull TTransport transport) { Objects.requireNonNull(key); Objects.requireNonNull(transport); synchronized (mTransports) { TTransport oldTransport = mTransports.put(key, transport); if (oldTransport != null) { oldTransport.unregister(); } Preconditions.checkState(transport.isRegistered()); boolean registered = false; try { if (oldTransport == null) { registerWithServer(transport); } else { reregisterWithServer(oldTransport, transport); } registered = true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } finally { if (!registered) { transport.unregister(); mTransports.remove(key); } } } } /** * Removes the transport with the given key, and makes a call to remove the transport server * side via {@link #unregisterWithServer(ListenerTransport)}. */ protected void unregisterListener(@NonNull Object key) { Objects.requireNonNull(key); synchronized (mTransports) { TTransport transport = mTransports.remove(key); if (transport == null) { return; } transport.unregister(); try { unregisterWithServer(transport); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * Removes the given transport with the given key if such a mapping exists. This only removes * the client registration, it does not make any calls to remove the transport server side. The * intended use is for when the transport is already removed server side and only client side * cleanup is necessary. */ protected void removeTransport(@NonNull Object key, @NonNull ListenerTransport<?> transport) { Objects.requireNonNull(key); Objects.requireNonNull(transport); synchronized (mTransports) { TTransport typedTransport = mTransports.get(key); if (typedTransport != transport) { return; } mTransports.remove(key); typedTransport.unregister(); } } } core/java/com/android/internal/listeners/ListenerTransportMultiplexer.java +6 −10 Original line number Original line Diff line number Diff line Loading @@ -21,13 +21,12 @@ import android.annotation.Nullable; import android.os.Build; import android.os.Build; import android.os.RemoteException; import android.os.RemoteException; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.IndentingPrintWriter; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions; import java.io.FileDescriptor; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.ArrayList; import java.util.Collection; import java.util.Collection; import java.util.Objects; import java.util.Objects; Loading @@ -38,8 +37,7 @@ import java.util.function.Consumer; * A listener multiplexer designed for use by client-side code. This class ensures that listeners * A listener multiplexer designed for use by client-side code. This class ensures that listeners * are never invoked while a lock is held. This class is only useful for multiplexing listeners - * are never invoked while a lock is held. This class is only useful for multiplexing listeners - * if all client listeners can be combined into a single server request, and all server results will * if all client listeners can be combined into a single server request, and all server results will * be delivered to all clients. If this is not the case, see {@link ListenerTransportManager} * be delivered to all clients. * instead. * * * By default, the multiplexer will replace requests on the server simply by registering the new * By default, the multiplexer will replace requests on the server simply by registering the new * request and trusting the server to know this is replacing the old request. If the server needs to * request and trusting the server to know this is replacing the old request. If the server needs to Loading Loading @@ -229,9 +227,7 @@ public abstract class ListenerTransportMultiplexer<TRequest, TListener> { /** /** * Dumps debug information. * Dumps debug information. */ */ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) { IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); ArrayMap<Object, RequestListenerTransport<TRequest, TListener>> registrations; ArrayMap<Object, RequestListenerTransport<TRequest, TListener>> registrations; synchronized (mLock) { synchronized (mLock) { registrations = mRegistrations; registrations = mRegistrations; Loading @@ -239,12 +235,12 @@ public abstract class ListenerTransportMultiplexer<TRequest, TListener> { ipw.print("service: "); ipw.print("service: "); if (mServiceRegistered) { if (mServiceRegistered) { if (mCurrentRequest == null) { if (mCurrentRequest == null) { pw.print("request registered"); ipw.print("request registered"); } else { } else { pw.print("request registered - " + mCurrentRequest); ipw.print("request registered - " + mCurrentRequest); } } } else { } else { pw.print("unregistered"); ipw.print("unregistered"); } } ipw.println(); ipw.println(); } } Loading location/java/android/location/ILocationCallback.aidl 0 → 100644 +28 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.location; import android.location.Location; /** * Listener for single locations. * {@hide} */ oneway interface ILocationCallback { void onLocation(in @nullable Location location); } Loading
core/java/com/android/internal/listeners/ListenerExecutor.java 0 → 100644 +132 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.listeners; import android.annotation.Nullable; import java.util.concurrent.Executor; import java.util.function.Supplier; /** * Interface (trait) for executing listener style operations on an executor. */ public interface ListenerExecutor { /** * An listener operation to perform. * * @param <TListener> listener type */ interface ListenerOperation<TListener> { /** * Performs the operation on the given listener. */ void operate(TListener listener) throws Exception; /** * Called before this operation is to be run. Some operations may be canceled before they * are run, in which case this method may not be called. {@link #onPostExecute(boolean)} * will only be run if this method was run. */ default void onPreExecute() {} /** * Called if the operation fails while running. Will not be invoked in the event of a * RuntimeException, which will propagate normally. Implementations of * {@link ListenerExecutor} have the option to override * {@link ListenerExecutor#onOperationFailure(ListenerOperation, Exception)} instead to * intercept failures at the class level. */ default void onFailure(Exception e) { // implementations should handle any exceptions that may be thrown throw new AssertionError(e); } /** * Called after the operation is run. This method will always be called if * {@link #onPreExecute()} is called. Success implies that the operation was run to * completion with no failures. */ default void onPostExecute(boolean success) {} /** * Called after this operation is complete (which does not imply that it was necessarily * run). Will always be called once per operation, no matter if the operation was run or * not. Success implies that the operation was run to completion with no failures. */ default void onComplete(boolean success) {} } /** * May be override to handle operation failures at a class level. Will not be invoked in the * event of a RuntimeException, which will propagate normally. */ default <TListener> void onOperationFailure(ListenerOperation<TListener> operation, Exception exception) { operation.onFailure(exception); } /** * Executes the given listener operation on the given executor, using the provided listener * supplier. If the supplier returns a null value, or a value during the operation that does not * match the value prior to the operation, then the operation is considered canceled. */ default <TListener> void executeSafely(Executor executor, Supplier<TListener> listenerSupplier, @Nullable ListenerOperation<TListener> operation) { if (operation == null) { return; } boolean executing = false; boolean preexecute = false; try { TListener listener = listenerSupplier.get(); if (listener == null) { return; } operation.onPreExecute(); preexecute = true; executor.execute(() -> { boolean success = false; try { if (listener == listenerSupplier.get()) { operation.operate(listener); success = true; } } catch (Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } else { onOperationFailure(operation, e); } } finally { operation.onPostExecute(success); operation.onComplete(success); } }); executing = true; } finally { if (!executing) { if (preexecute) { operation.onPostExecute(false); } operation.onComplete(false); } } } }
core/java/com/android/internal/listeners/ListenerTransport.java +0 −4 Original line number Original line Diff line number Diff line Loading @@ -45,10 +45,6 @@ public class ListenerTransport<TListener> { mListener = listener; mListener = listener; } } final boolean isRegistered() { return mListener != null; } /** /** * Prevents any listener invocations that happen-after this call. * Prevents any listener invocations that happen-after this call. */ */ Loading
core/java/com/android/internal/listeners/ListenerTransportManager.javadeleted 100644 → 0 +0 −145 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.listeners; import android.annotation.NonNull; import android.os.RemoteException; import android.util.ArrayMap; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import java.util.Objects; /** * A listener manager which tracks listeners along with their keys. This class enforces proper use * of transport objects and ensure unregistration race conditions are handled properly. If listeners * should be multiplexed before being sent to the server, see {@link ListenerTransportMultiplexer} * instead. * * @param <TTransport> transport type */ public abstract class ListenerTransportManager<TTransport extends ListenerTransport<?>> { @GuardedBy("mTransports") private final ArrayMap<Object, TTransport> mTransports = new ArrayMap<>(); /** * Should be implemented to register the transport with the server. * * @see #reregisterWithServer(ListenerTransport, ListenerTransport) */ protected abstract void registerWithServer(TTransport transport) throws RemoteException; /** * Invoked when the server already has a transport registered for a key, and it is being * replaced with a new transport. The default implementation unregisters the old transport, then * registers the new transport, but this may be overridden by subclasses in order to reregister * more efficiently. */ protected void reregisterWithServer(TTransport oldTransport, TTransport newTransport) throws RemoteException { unregisterWithServer(oldTransport); registerWithServer(newTransport); } /** * Should be implemented to unregister the transport from the server. */ protected abstract void unregisterWithServer(TTransport transport) throws RemoteException; /** * Adds a new transport with the given key and makes a call to add the transport server side. If * a transport already exists with that key, it will be replaced by the new transport and * {@link #reregisterWithServer(ListenerTransport, ListenerTransport)} will be invoked to * replace the old transport with the new transport server side. If no transport exists with * that key, it will be added server side via {@link #registerWithServer(ListenerTransport)}. */ protected void registerListener(@NonNull Object key, @NonNull TTransport transport) { Objects.requireNonNull(key); Objects.requireNonNull(transport); synchronized (mTransports) { TTransport oldTransport = mTransports.put(key, transport); if (oldTransport != null) { oldTransport.unregister(); } Preconditions.checkState(transport.isRegistered()); boolean registered = false; try { if (oldTransport == null) { registerWithServer(transport); } else { reregisterWithServer(oldTransport, transport); } registered = true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } finally { if (!registered) { transport.unregister(); mTransports.remove(key); } } } } /** * Removes the transport with the given key, and makes a call to remove the transport server * side via {@link #unregisterWithServer(ListenerTransport)}. */ protected void unregisterListener(@NonNull Object key) { Objects.requireNonNull(key); synchronized (mTransports) { TTransport transport = mTransports.remove(key); if (transport == null) { return; } transport.unregister(); try { unregisterWithServer(transport); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * Removes the given transport with the given key if such a mapping exists. This only removes * the client registration, it does not make any calls to remove the transport server side. The * intended use is for when the transport is already removed server side and only client side * cleanup is necessary. */ protected void removeTransport(@NonNull Object key, @NonNull ListenerTransport<?> transport) { Objects.requireNonNull(key); Objects.requireNonNull(transport); synchronized (mTransports) { TTransport typedTransport = mTransports.get(key); if (typedTransport != transport) { return; } mTransports.remove(key); typedTransport.unregister(); } } }
core/java/com/android/internal/listeners/ListenerTransportMultiplexer.java +6 −10 Original line number Original line Diff line number Diff line Loading @@ -21,13 +21,12 @@ import android.annotation.Nullable; import android.os.Build; import android.os.Build; import android.os.RemoteException; import android.os.RemoteException; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.IndentingPrintWriter; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions; import java.io.FileDescriptor; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.ArrayList; import java.util.Collection; import java.util.Collection; import java.util.Objects; import java.util.Objects; Loading @@ -38,8 +37,7 @@ import java.util.function.Consumer; * A listener multiplexer designed for use by client-side code. This class ensures that listeners * A listener multiplexer designed for use by client-side code. This class ensures that listeners * are never invoked while a lock is held. This class is only useful for multiplexing listeners - * are never invoked while a lock is held. This class is only useful for multiplexing listeners - * if all client listeners can be combined into a single server request, and all server results will * if all client listeners can be combined into a single server request, and all server results will * be delivered to all clients. If this is not the case, see {@link ListenerTransportManager} * be delivered to all clients. * instead. * * * By default, the multiplexer will replace requests on the server simply by registering the new * By default, the multiplexer will replace requests on the server simply by registering the new * request and trusting the server to know this is replacing the old request. If the server needs to * request and trusting the server to know this is replacing the old request. If the server needs to Loading Loading @@ -229,9 +227,7 @@ public abstract class ListenerTransportMultiplexer<TRequest, TListener> { /** /** * Dumps debug information. * Dumps debug information. */ */ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) { IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); ArrayMap<Object, RequestListenerTransport<TRequest, TListener>> registrations; ArrayMap<Object, RequestListenerTransport<TRequest, TListener>> registrations; synchronized (mLock) { synchronized (mLock) { registrations = mRegistrations; registrations = mRegistrations; Loading @@ -239,12 +235,12 @@ public abstract class ListenerTransportMultiplexer<TRequest, TListener> { ipw.print("service: "); ipw.print("service: "); if (mServiceRegistered) { if (mServiceRegistered) { if (mCurrentRequest == null) { if (mCurrentRequest == null) { pw.print("request registered"); ipw.print("request registered"); } else { } else { pw.print("request registered - " + mCurrentRequest); ipw.print("request registered - " + mCurrentRequest); } } } else { } else { pw.print("unregistered"); ipw.print("unregistered"); } } ipw.println(); ipw.println(); } } Loading
location/java/android/location/ILocationCallback.aidl 0 → 100644 +28 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.location; import android.location.Location; /** * Listener for single locations. * {@hide} */ oneway interface ILocationCallback { void onLocation(in @nullable Location location); }