diff options
author | Eugene Susla <eugenesusla@google.com> | 2017-06-23 17:25:24 -0700 |
---|---|---|
committer | Eugene Susla <eugenesusla@google.com> | 2017-12-05 10:46:59 -0800 |
commit | 2f5ee71ec851b1149b4e10ec211ad520cd73776e (patch) | |
tree | 3ecf658e14233141e3bb739070dc454e50d79502 | |
parent | e4cf6bf4745754615b19d95a90d809889c5e4b43 (diff) |
PooledLambda
This introduces PooledLambda - a way of obtaining lambdas without the
allocations overhead.
See PooledLambda javadoc for a guide and PooledLambdaSample for code samples
of useful usages.
Test: ensure samples of PooledLambdaSample work as described.
Change-Id: I46f8ad27bc1de07e19f6e39f89d2cafe4238497a
23 files changed, 2014 insertions, 246 deletions
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index b5bcd02c1a18..52e1fc81635b 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -298,7 +298,7 @@ public class Binder implements IBinder { long callingIdentity = clearCallingIdentity(); Throwable throwableToPropagate = null; try { - action.run(); + action.runOrThrow(); } catch (Throwable throwable) { throwableToPropagate = throwable; } finally { @@ -322,7 +322,7 @@ public class Binder implements IBinder { long callingIdentity = clearCallingIdentity(); Throwable throwableToPropagate = null; try { - return action.get(); + return action.getOrThrow(); } catch (Throwable throwable) { throwableToPropagate = throwable; return null; // overridden by throwing in finally block diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java index d066db1fc4cc..b303e10fa64b 100644 --- a/core/java/android/os/Message.java +++ b/core/java/android/os/Message.java @@ -109,7 +109,9 @@ public final class Message implements Parcelable { // sometimes we store linked lists of these things /*package*/ Message next; - private static final Object sPoolSync = new Object(); + + /** @hide */ + public static final Object sPoolSync = new Object(); private static Message sPool; private static int sPoolSize = 0; @@ -370,6 +372,12 @@ public final class Message implements Parcelable { return callback; } + /** @hide */ + public Message setCallback(Runnable r) { + callback = r; + return this; + } + /** * Obtains a Bundle of arbitrary data associated with this * event, lazily creating it if necessary. Set this value by calling @@ -411,6 +419,16 @@ public final class Message implements Parcelable { } /** + * Chainable setter for {@link #what} + * + * @hide + */ + public Message setWhat(int what) { + this.what = what; + return this; + } + + /** * Sends this Message to the Handler specified by {@link #getTarget}. * Throws a null pointer exception if this field has not been set. */ diff --git a/core/java/android/util/Pools.java b/core/java/android/util/Pools.java index 70581be80dce..f0b7e01dae48 100644 --- a/core/java/android/util/Pools.java +++ b/core/java/android/util/Pools.java @@ -130,22 +130,29 @@ public final class Pools { } /** - * Synchronized) pool of objects. + * Synchronized pool of objects. * * @param <T> The pooled type. */ public static class SynchronizedPool<T> extends SimplePool<T> { - private final Object mLock = new Object(); + private final Object mLock; /** * Creates a new instance. * * @param maxPoolSize The max pool size. + * @param lock an optional custom object to synchronize on * * @throws IllegalArgumentException If the max pool size is less than zero. */ - public SynchronizedPool(int maxPoolSize) { + public SynchronizedPool(int maxPoolSize, Object lock) { super(maxPoolSize); + mLock = lock; + } + + /** @see #SynchronizedPool(int, Object) */ + public SynchronizedPool(int maxPoolSize) { + this(maxPoolSize, new Object()); } @Override diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java index f0b47de8be98..f983de17e0b1 100644 --- a/core/java/com/android/internal/util/CollectionUtils.java +++ b/core/java/com/android/internal/util/CollectionUtils.java @@ -30,7 +30,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.function.*; +import java.util.function.Function; import java.util.stream.Stream; /** diff --git a/core/java/com/android/internal/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java index cdef97e84f62..eb92c1c0dfb2 100644 --- a/core/java/com/android/internal/util/FunctionalUtils.java +++ b/core/java/com/android/internal/util/FunctionalUtils.java @@ -32,7 +32,7 @@ public class FunctionalUtils { */ @FunctionalInterface public interface ThrowingRunnable { - void run() throws Exception; + void runOrThrow() throws Exception; } /** @@ -43,7 +43,7 @@ public class FunctionalUtils { */ @FunctionalInterface public interface ThrowingSupplier<T> { - T get() throws Exception; + T getOrThrow() throws Exception; } /** diff --git a/core/java/com/android/internal/util/function/QuadConsumer.java b/core/java/com/android/internal/util/function/QuadConsumer.java new file mode 100644 index 000000000000..d899c01b16c6 --- /dev/null +++ b/core/java/com/android/internal/util/function/QuadConsumer.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2017 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.util.function; + + +import java.util.function.Consumer; + +/** + * A 4-argument {@link Consumer} + * + * @hide + */ +public interface QuadConsumer<A, B, C, D> { + void accept(A a, B b, C c, D d); +} diff --git a/core/java/com/android/internal/util/function/QuadFunction.java b/core/java/com/android/internal/util/function/QuadFunction.java new file mode 100644 index 000000000000..700d9536409d --- /dev/null +++ b/core/java/com/android/internal/util/function/QuadFunction.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2017 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.util.function; + + +import java.util.function.Function; + +/** + * A 4-argument {@link Function} + * + * @hide + */ +public interface QuadFunction<A, B, C, D, R> { + R apply(A a, B b, C c, D d); +} diff --git a/core/java/com/android/internal/util/function/QuadPredicate.java b/core/java/com/android/internal/util/function/QuadPredicate.java new file mode 100644 index 000000000000..512c98ba1e47 --- /dev/null +++ b/core/java/com/android/internal/util/function/QuadPredicate.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2017 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.util.function; + + +import java.util.function.Predicate; + +/** + * A 4-argument {@link Predicate} + * + * @hide + */ +public interface QuadPredicate<A, B, C, D> { + boolean test(A a, B b, C c, D d); +} diff --git a/core/java/com/android/internal/util/function/TriConsumer.java b/core/java/com/android/internal/util/function/TriConsumer.java new file mode 100644 index 000000000000..40d614ec5aff --- /dev/null +++ b/core/java/com/android/internal/util/function/TriConsumer.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2017 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.util.function; + + +import java.util.function.Consumer; + +/** + * A 3-argument {@link Consumer} + * + * @hide + */ +public interface TriConsumer<A, B, C> { + void accept(A a, B b, C c); +} diff --git a/core/java/com/android/internal/util/function/TriFunction.java b/core/java/com/android/internal/util/function/TriFunction.java new file mode 100644 index 000000000000..2b1df86e72e2 --- /dev/null +++ b/core/java/com/android/internal/util/function/TriFunction.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2017 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.util.function; + + +import java.util.function.Function; + +/** + * A 3-argument {@link Function} + * + * @hide + */ +public interface TriFunction<A, B, C, R> { + R apply(A a, B b, C c); +} diff --git a/core/java/com/android/internal/util/function/TriPredicate.java b/core/java/com/android/internal/util/function/TriPredicate.java new file mode 100644 index 000000000000..d9cd9683ee26 --- /dev/null +++ b/core/java/com/android/internal/util/function/TriPredicate.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2017 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.util.function; + + +import java.util.function.Predicate; + +/** + * A 3-argument {@link Predicate} + * + * @hide + */ +public interface TriPredicate<A, B, C> { + boolean test(A a, B b, C c); +} diff --git a/core/java/com/android/internal/util/function/pooled/ArgumentPlaceholder.java b/core/java/com/android/internal/util/function/pooled/ArgumentPlaceholder.java new file mode 100644 index 000000000000..cf86b7171864 --- /dev/null +++ b/core/java/com/android/internal/util/function/pooled/ArgumentPlaceholder.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017 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.util.function.pooled; + +/** + * A placeholder for an argument of type {@code R} + * + * @see PooledLambda + * @hide + */ +public final class ArgumentPlaceholder<R> { + private ArgumentPlaceholder() {} + static final ArgumentPlaceholder<?> INSTANCE = new ArgumentPlaceholder<>(); + + @Override + public String toString() { + return "_"; + } +} diff --git a/core/java/com/android/internal/util/function/pooled/OmniFunction.java b/core/java/com/android/internal/util/function/pooled/OmniFunction.java new file mode 100755 index 000000000000..c0f506ec889f --- /dev/null +++ b/core/java/com/android/internal/util/function/pooled/OmniFunction.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2017 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.util.function.pooled; + +import com.android.internal.util.FunctionalUtils.ThrowingRunnable; +import com.android.internal.util.FunctionalUtils.ThrowingSupplier; +import com.android.internal.util.function.QuadConsumer; +import com.android.internal.util.function.QuadFunction; +import com.android.internal.util.function.TriConsumer; +import com.android.internal.util.function.TriFunction; + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import java.util.function.Function; + +/** + * An interface implementing all supported function interfaces, delegating each to {@link #invoke} + * + * @hide + */ +abstract class OmniFunction<A, B, C, D, R> implements + PooledFunction<A, R>, BiFunction<A, B, R>, TriFunction<A, B, C, R>, + QuadFunction<A, B, C, D, R>, + PooledConsumer<A>, BiConsumer<A, B>, TriConsumer<A, B, C>, QuadConsumer<A, B, C, D>, + PooledPredicate<A>, BiPredicate<A, B>, + PooledSupplier<R>, PooledRunnable, + ThrowingRunnable, ThrowingSupplier<R>, + PooledSupplier.OfInt, PooledSupplier.OfLong, PooledSupplier.OfDouble { + + abstract R invoke(A a, B b, C c, D d); + + @Override + public R apply(A o, B o2) { + return invoke(o, o2, null, null); + } + + @Override + public R apply(A o) { + return invoke(o, null, null, null); + } + + abstract public <V> OmniFunction<A, B, C, D, V> andThen(Function<? super R, ? extends V> after); + abstract public OmniFunction<A, B, C, D, R> negate(); + + @Override + public void accept(A o, B o2) { + invoke(o, o2, null, null); + } + + @Override + public void accept(A o) { + invoke(o, null, null, null); + } + + @Override + public void run() { + invoke(null, null, null, null); + } + + @Override + public R get() { + return invoke(null, null, null, null); + } + + @Override + public boolean test(A o, B o2) { + return (Boolean) invoke(o, o2, null, null); + } + + @Override + public boolean test(A o) { + return (Boolean) invoke(o, null, null, null); + } + + @Override + public PooledRunnable asRunnable() { + return this; + } + + @Override + public PooledConsumer<A> asConsumer() { + return this; + } + + @Override + public R apply(A a, B b, C c) { + return invoke(a, b, c, null); + } + + @Override + public void accept(A a, B b, C c) { + invoke(a, b, c, null); + } + + @Override + public R apply(A a, B b, C c, D d) { + return invoke(a, b, c, d); + } + + @Override + public void accept(A a, B b, C c, D d) { + invoke(a, b, c, d); + } + + @Override + public void runOrThrow() throws Exception { + run(); + } + + @Override + public R getOrThrow() throws Exception { + return get(); + } + + @Override + abstract public OmniFunction<A, B, C, D, R> recycleOnUse(); +} diff --git a/core/java/com/android/internal/util/function/pooled/PooledConsumer.java b/core/java/com/android/internal/util/function/pooled/PooledConsumer.java new file mode 100644 index 000000000000..f66586ee6791 --- /dev/null +++ b/core/java/com/android/internal/util/function/pooled/PooledConsumer.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2017 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.util.function.pooled; + +import java.util.function.Consumer; + +/** + * {@link Consumer} + {@link PooledLambda} + * + * @see PooledLambda + * @hide + */ +public interface PooledConsumer<T> extends PooledLambda, Consumer<T> { + + /** @inheritDoc */ + PooledConsumer<T> recycleOnUse(); +} diff --git a/core/java/com/android/internal/util/function/pooled/PooledFunction.java b/core/java/com/android/internal/util/function/pooled/PooledFunction.java new file mode 100644 index 000000000000..1f166fafc7e6 --- /dev/null +++ b/core/java/com/android/internal/util/function/pooled/PooledFunction.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 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.util.function.pooled; + +import java.util.function.Function; + +/** + * {@link Function} + {@link PooledLambda} + * + * @see PooledLambda + * @hide + */ +public interface PooledFunction<A, R> extends PooledLambda, Function<A, R> { + + /** + * Ignores the result + */ + PooledConsumer<A> asConsumer(); + + /** @inheritDoc */ + PooledFunction<A, R> recycleOnUse(); +} diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java new file mode 100755 index 000000000000..17b140dec396 --- /dev/null +++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java @@ -0,0 +1,813 @@ +/* + * Copyright (C) 2017 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.util.function.pooled; + +import static com.android.internal.util.function.pooled.PooledLambdaImpl.acquire; +import static com.android.internal.util.function.pooled.PooledLambdaImpl.acquireConstSupplier; + +import android.os.Message; + +import com.android.internal.util.function.QuadConsumer; +import com.android.internal.util.function.QuadFunction; +import com.android.internal.util.function.TriConsumer; +import com.android.internal.util.function.TriFunction; +import com.android.internal.util.function.pooled.PooledLambdaImpl.LambdaType.ReturnType; + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + +/** + * A recyclable anonymous function. + * Allows obtaining {@link Function}s/{@link Runnable}s/{@link Supplier}s/etc. without allocating a + * new instance each time + * + * This exploits the mechanic that stateless lambdas (such as plain/non-bound method references) + * get translated into a singleton instance, making it possible to create a recyclable container + * ({@link PooledLambdaImpl}) holding a reference to such a singleton function, as well as + * (possibly partial) arguments required for its invocation. + * + * To obtain an instance, use one of the factory methods in this class. + * + * You can call {@link #recycleOnUse} to make the instance automatically recycled upon invocation, + * making if effectively <b>one-time use</b>. + * This is often the behavior you want, as it allows to not worry about manual recycling. + * Some notable examples: {@link android.os.Handler#post(Runnable)}, + * {@link android.app.Activity#runOnUiThread(Runnable)}, {@link android.view.View#post(Runnable)} + * + * For factories of functions that take further arguments, the corresponding 'missing' argument's + * position is marked by an argument of type {@link ArgumentPlaceholder} with the type parameter + * corresponding to missing argument's type. + * You can fill the 'missing argument' spot with {@link #__()} + * (which is the factory function for {@link ArgumentPlaceholder}) + * + * @hide + */ +@SuppressWarnings({"unchecked", "unused", "WeakerAccess"}) +public interface PooledLambda { + + /** + * Recycles this instance. No-op if already recycled. + */ + void recycle(); + + /** + * Makes this instance automatically {@link #recycle} itself after the first call. + * + * @return this instance for convenience + */ + PooledLambda recycleOnUse(); + + + // Factories + + /** + * @return {@link ArgumentPlaceholder} with the inferred type parameter value + */ + static <R> ArgumentPlaceholder<R> __() { + return (ArgumentPlaceholder<R>) ArgumentPlaceholder.INSTANCE; + } + + /** + * @param typeHint the explicitly specified type of the missing argument + * @return {@link ArgumentPlaceholder} with the specified type parameter value + */ + static <R> ArgumentPlaceholder<R> __(Class<R> typeHint) { + return __(); + } + + /** + * Wraps the given value into a {@link PooledSupplier} + * + * @param value a value to wrap + * @return a pooled supplier of {@code value} + */ + static <R> PooledSupplier<R> obtainSupplier(R value) { + PooledLambdaImpl r = acquireConstSupplier(ReturnType.OBJECT); + r.mFunc = value; + return r; + } + + /** + * Wraps the given value into a {@link PooledSupplier} + * + * @param value a value to wrap + * @return a pooled supplier of {@code value} + */ + static PooledSupplier.OfInt obtainSupplier(int value) { + PooledLambdaImpl r = acquireConstSupplier(ReturnType.INT); + r.mConstValue = value; + return r; + } + + /** + * Wraps the given value into a {@link PooledSupplier} + * + * @param value a value to wrap + * @return a pooled supplier of {@code value} + */ + static PooledSupplier.OfLong obtainSupplier(long value) { + PooledLambdaImpl r = acquireConstSupplier(ReturnType.LONG); + r.mConstValue = value; + return r; + } + + /** + * Wraps the given value into a {@link PooledSupplier} + * + * @param value a value to wrap + * @return a pooled supplier of {@code value} + */ + static PooledSupplier.OfDouble obtainSupplier(double value) { + PooledLambdaImpl r = acquireConstSupplier(ReturnType.DOUBLE); + r.mConstValue = Double.doubleToRawLongBits(value); + return r; + } + + /** + * {@link PooledRunnable} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @return a {@link PooledRunnable}, equivalent to lambda: + * {@code () -> function(arg1) } + */ + static <A> PooledRunnable obtainRunnable( + Consumer<? super A> function, + A arg1) { + return acquire(PooledLambdaImpl.sPool, + function, 1, 0, ReturnType.VOID, arg1, null, null, null); + } + + /** + * {@link PooledSupplier} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @return a {@link PooledSupplier}, equivalent to lambda: + * {@code () -> function(arg1) } + */ + static <A> PooledSupplier<Boolean> obtainSupplier( + Predicate<? super A> function, + A arg1) { + return acquire(PooledLambdaImpl.sPool, + function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null); + } + + /** + * {@link PooledSupplier} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @return a {@link PooledSupplier}, equivalent to lambda: + * {@code () -> function(arg1) } + */ + static <A, R> PooledSupplier<R> obtainSupplier( + Function<? super A, ? extends R> function, + A arg1) { + return acquire(PooledLambdaImpl.sPool, + function, 1, 0, ReturnType.OBJECT, arg1, null, null, null); + } + + /** + * Factory of {@link Message}s that contain an + * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its + * {@link Message#getCallback internal callback}. + * + * The callback is equivalent to one obtainable via + * {@link #obtainRunnable(Consumer, Object)} + * + * Note that using this method with {@link android.os.Handler#handleMessage} + * is more efficient than the alternative of {@link android.os.Handler#post} + * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points + * when obtaining {@link Message} and {@link PooledRunnable} from pools separately + * + * You may optionally set a {@link Message#what} for the message if you want to be + * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise + * there's no need to do so + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @return a {@link Message} invoking {@code function(arg1) } when handled + */ + static <A> Message obtainMessage( + Consumer<? super A> function, + A arg1) { + synchronized (Message.sPoolSync) { + PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, + function, 1, 0, ReturnType.VOID, arg1, null, null, null); + return Message.obtain().setCallback(callback.recycleOnUse()); + } + } + + /** + * {@link PooledRunnable} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @return a {@link PooledRunnable}, equivalent to lambda: + * {@code () -> function(arg1, arg2) } + */ + static <A, B> PooledRunnable obtainRunnable( + BiConsumer<? super A, ? super B> function, + A arg1, B arg2) { + return acquire(PooledLambdaImpl.sPool, + function, 2, 0, ReturnType.VOID, arg1, arg2, null, null); + } + + /** + * {@link PooledSupplier} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @return a {@link PooledSupplier}, equivalent to lambda: + * {@code () -> function(arg1, arg2) } + */ + static <A, B> PooledSupplier<Boolean> obtainSupplier( + BiPredicate<? super A, ? super B> function, + A arg1, B arg2) { + return acquire(PooledLambdaImpl.sPool, + function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null); + } + + /** + * {@link PooledSupplier} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @return a {@link PooledSupplier}, equivalent to lambda: + * {@code () -> function(arg1, arg2) } + */ + static <A, B, R> PooledSupplier<R> obtainSupplier( + BiFunction<? super A, ? super B, ? extends R> function, + A arg1, B arg2) { + return acquire(PooledLambdaImpl.sPool, + function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null); + } + + /** + * {@link PooledConsumer} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 placeholder for a missing argument. Use {@link #__} to get one + * @param arg2 parameter supplied to {@code function} on call + * @return a {@link PooledConsumer}, equivalent to lambda: + * {@code (arg1) -> function(arg1, arg2) } + */ + static <A, B> PooledConsumer<A> obtainConsumer( + BiConsumer<? super A, ? super B> function, + ArgumentPlaceholder<A> arg1, B arg2) { + return acquire(PooledLambdaImpl.sPool, + function, 2, 1, ReturnType.VOID, arg1, arg2, null, null); + } + + /** + * {@link PooledPredicate} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 placeholder for a missing argument. Use {@link #__} to get one + * @param arg2 parameter supplied to {@code function} on call + * @return a {@link PooledPredicate}, equivalent to lambda: + * {@code (arg1) -> function(arg1, arg2) } + */ + static <A, B> PooledPredicate<A> obtainPredicate( + BiPredicate<? super A, ? super B> function, + ArgumentPlaceholder<A> arg1, B arg2) { + return acquire(PooledLambdaImpl.sPool, + function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null); + } + + /** + * {@link PooledFunction} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 placeholder for a missing argument. Use {@link #__} to get one + * @param arg2 parameter supplied to {@code function} on call + * @return a {@link PooledFunction}, equivalent to lambda: + * {@code (arg1) -> function(arg1, arg2) } + */ + static <A, B, R> PooledFunction<A, R> obtainFunction( + BiFunction<? super A, ? super B, ? extends R> function, + ArgumentPlaceholder<A> arg1, B arg2) { + return acquire(PooledLambdaImpl.sPool, + function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null); + } + + /** + * {@link PooledConsumer} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 placeholder for a missing argument. Use {@link #__} to get one + * @return a {@link PooledConsumer}, equivalent to lambda: + * {@code (arg2) -> function(arg1, arg2) } + */ + static <A, B> PooledConsumer<B> obtainConsumer( + BiConsumer<? super A, ? super B> function, + A arg1, ArgumentPlaceholder<B> arg2) { + return acquire(PooledLambdaImpl.sPool, + function, 2, 1, ReturnType.VOID, arg1, arg2, null, null); + } + + /** + * {@link PooledPredicate} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 placeholder for a missing argument. Use {@link #__} to get one + * @return a {@link PooledPredicate}, equivalent to lambda: + * {@code (arg2) -> function(arg1, arg2) } + */ + static <A, B> PooledPredicate<B> obtainPredicate( + BiPredicate<? super A, ? super B> function, + A arg1, ArgumentPlaceholder<B> arg2) { + return acquire(PooledLambdaImpl.sPool, + function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null); + } + + /** + * {@link PooledFunction} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 placeholder for a missing argument. Use {@link #__} to get one + * @return a {@link PooledFunction}, equivalent to lambda: + * {@code (arg2) -> function(arg1, arg2) } + */ + static <A, B, R> PooledFunction<B, R> obtainFunction( + BiFunction<? super A, ? super B, ? extends R> function, + A arg1, ArgumentPlaceholder<B> arg2) { + return acquire(PooledLambdaImpl.sPool, + function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null); + } + + /** + * Factory of {@link Message}s that contain an + * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its + * {@link Message#getCallback internal callback}. + * + * The callback is equivalent to one obtainable via + * {@link #obtainRunnable(BiConsumer, Object, Object)} + * + * Note that using this method with {@link android.os.Handler#handleMessage} + * is more efficient than the alternative of {@link android.os.Handler#post} + * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points + * when obtaining {@link Message} and {@link PooledRunnable} from pools separately + * + * You may optionally set a {@link Message#what} for the message if you want to be + * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise + * there's no need to do so + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @return a {@link Message} invoking {@code function(arg1, arg2) } when handled + */ + static <A, B> Message obtainMessage( + BiConsumer<? super A, ? super B> function, + A arg1, B arg2) { + synchronized (Message.sPoolSync) { + PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, + function, 2, 0, ReturnType.VOID, arg1, arg2, null, null); + return Message.obtain().setCallback(callback.recycleOnUse()); + } + } + + /** + * {@link PooledRunnable} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @return a {@link PooledRunnable}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3) } + */ + static <A, B, C> PooledRunnable obtainRunnable( + TriConsumer<? super A, ? super B, ? super C> function, + A arg1, B arg2, C arg3) { + return acquire(PooledLambdaImpl.sPool, + function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null); + } + + /** + * {@link PooledSupplier} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @return a {@link PooledSupplier}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3) } + */ + static <A, B, C, R> PooledSupplier<R> obtainSupplier( + TriFunction<? super A, ? super B, ? super C, ? extends R> function, + A arg1, B arg2, C arg3) { + return acquire(PooledLambdaImpl.sPool, + function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null); + } + + /** + * {@link PooledConsumer} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 placeholder for a missing argument. Use {@link #__} to get one + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @return a {@link PooledConsumer}, equivalent to lambda: + * {@code (arg1) -> function(arg1, arg2, arg3) } + */ + static <A, B, C> PooledConsumer<A> obtainConsumer( + TriConsumer<? super A, ? super B, ? super C> function, + ArgumentPlaceholder<A> arg1, B arg2, C arg3) { + return acquire(PooledLambdaImpl.sPool, + function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null); + } + + /** + * {@link PooledFunction} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 placeholder for a missing argument. Use {@link #__} to get one + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @return a {@link PooledFunction}, equivalent to lambda: + * {@code (arg1) -> function(arg1, arg2, arg3) } + */ + static <A, B, C, R> PooledFunction<A, R> obtainFunction( + TriFunction<? super A, ? super B, ? super C, ? extends R> function, + ArgumentPlaceholder<A> arg1, B arg2, C arg3) { + return acquire(PooledLambdaImpl.sPool, + function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null); + } + + /** + * {@link PooledConsumer} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 placeholder for a missing argument. Use {@link #__} to get one + * @param arg3 parameter supplied to {@code function} on call + * @return a {@link PooledConsumer}, equivalent to lambda: + * {@code (arg2) -> function(arg1, arg2, arg3) } + */ + static <A, B, C> PooledConsumer<B> obtainConsumer( + TriConsumer<? super A, ? super B, ? super C> function, + A arg1, ArgumentPlaceholder<B> arg2, C arg3) { + return acquire(PooledLambdaImpl.sPool, + function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null); + } + + /** + * {@link PooledFunction} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 placeholder for a missing argument. Use {@link #__} to get one + * @param arg3 parameter supplied to {@code function} on call + * @return a {@link PooledFunction}, equivalent to lambda: + * {@code (arg2) -> function(arg1, arg2, arg3) } + */ + static <A, B, C, R> PooledFunction<B, R> obtainFunction( + TriFunction<? super A, ? super B, ? super C, ? extends R> function, + A arg1, ArgumentPlaceholder<B> arg2, C arg3) { + return acquire(PooledLambdaImpl.sPool, + function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null); + } + + /** + * {@link PooledConsumer} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 placeholder for a missing argument. Use {@link #__} to get one + * @return a {@link PooledConsumer}, equivalent to lambda: + * {@code (arg3) -> function(arg1, arg2, arg3) } + */ + static <A, B, C> PooledConsumer<C> obtainConsumer( + TriConsumer<? super A, ? super B, ? super C> function, + A arg1, B arg2, ArgumentPlaceholder<C> arg3) { + return acquire(PooledLambdaImpl.sPool, + function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null); + } + + /** + * {@link PooledFunction} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 placeholder for a missing argument. Use {@link #__} to get one + * @return a {@link PooledFunction}, equivalent to lambda: + * {@code (arg3) -> function(arg1, arg2, arg3) } + */ + static <A, B, C, R> PooledFunction<C, R> obtainFunction( + TriFunction<? super A, ? super B, ? super C, ? extends R> function, + A arg1, B arg2, ArgumentPlaceholder<C> arg3) { + return acquire(PooledLambdaImpl.sPool, + function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null); + } + + /** + * Factory of {@link Message}s that contain an + * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its + * {@link Message#getCallback internal callback}. + * + * The callback is equivalent to one obtainable via + * {@link #obtainRunnable(TriConsumer, Object, Object, Object)} + * + * Note that using this method with {@link android.os.Handler#handleMessage} + * is more efficient than the alternative of {@link android.os.Handler#post} + * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points + * when obtaining {@link Message} and {@link PooledRunnable} from pools separately + * + * You may optionally set a {@link Message#what} for the message if you want to be + * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise + * there's no need to do so + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @return a {@link Message} invoking {@code function(arg1, arg2, arg3) } when handled + */ + static <A, B, C> Message obtainMessage( + TriConsumer<? super A, ? super B, ? super C> function, + A arg1, B arg2, C arg3) { + synchronized (Message.sPoolSync) { + PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, + function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null); + return Message.obtain().setCallback(callback.recycleOnUse()); + } + } + + /** + * {@link PooledRunnable} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @return a {@link PooledRunnable}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4) } + */ + static <A, B, C, D> PooledRunnable obtainRunnable( + QuadConsumer<? super A, ? super B, ? super C, ? super D> function, + A arg1, B arg2, C arg3, D arg4) { + return acquire(PooledLambdaImpl.sPool, + function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4); + } + + /** + * {@link PooledSupplier} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @return a {@link PooledSupplier}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4) } + */ + static <A, B, C, D, R> PooledSupplier<R> obtainSupplier( + QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function, + A arg1, B arg2, C arg3, D arg4) { + return acquire(PooledLambdaImpl.sPool, + function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4); + } + + /** + * {@link PooledConsumer} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 placeholder for a missing argument. Use {@link #__} to get one + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @return a {@link PooledConsumer}, equivalent to lambda: + * {@code (arg1) -> function(arg1, arg2, arg3, arg4) } + */ + static <A, B, C, D> PooledConsumer<A> obtainConsumer( + QuadConsumer<? super A, ? super B, ? super C, ? super D> function, + ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) { + return acquire(PooledLambdaImpl.sPool, + function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4); + } + + /** + * {@link PooledFunction} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 placeholder for a missing argument. Use {@link #__} to get one + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @return a {@link PooledFunction}, equivalent to lambda: + * {@code (arg1) -> function(arg1, arg2, arg3, arg4) } + */ + static <A, B, C, D, R> PooledFunction<A, R> obtainFunction( + QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function, + ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) { + return acquire(PooledLambdaImpl.sPool, + function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4); + } + + /** + * {@link PooledConsumer} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 placeholder for a missing argument. Use {@link #__} to get one + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @return a {@link PooledConsumer}, equivalent to lambda: + * {@code (arg2) -> function(arg1, arg2, arg3, arg4) } + */ + static <A, B, C, D> PooledConsumer<B> obtainConsumer( + QuadConsumer<? super A, ? super B, ? super C, ? super D> function, + A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) { + return acquire(PooledLambdaImpl.sPool, + function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4); + } + + /** + * {@link PooledFunction} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 placeholder for a missing argument. Use {@link #__} to get one + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @return a {@link PooledFunction}, equivalent to lambda: + * {@code (arg2) -> function(arg1, arg2, arg3, arg4) } + */ + static <A, B, C, D, R> PooledFunction<B, R> obtainFunction( + QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function, + A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) { + return acquire(PooledLambdaImpl.sPool, + function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4); + } + + /** + * {@link PooledConsumer} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 placeholder for a missing argument. Use {@link #__} to get one + * @param arg4 parameter supplied to {@code function} on call + * @return a {@link PooledConsumer}, equivalent to lambda: + * {@code (arg3) -> function(arg1, arg2, arg3, arg4) } + */ + static <A, B, C, D> PooledConsumer<C> obtainConsumer( + QuadConsumer<? super A, ? super B, ? super C, ? super D> function, + A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) { + return acquire(PooledLambdaImpl.sPool, + function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4); + } + + /** + * {@link PooledFunction} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 placeholder for a missing argument. Use {@link #__} to get one + * @param arg4 parameter supplied to {@code function} on call + * @return a {@link PooledFunction}, equivalent to lambda: + * {@code (arg3) -> function(arg1, arg2, arg3, arg4) } + */ + static <A, B, C, D, R> PooledFunction<C, R> obtainFunction( + QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function, + A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) { + return acquire(PooledLambdaImpl.sPool, + function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4); + } + + /** + * {@link PooledConsumer} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 placeholder for a missing argument. Use {@link #__} to get one + * @return a {@link PooledConsumer}, equivalent to lambda: + * {@code (arg4) -> function(arg1, arg2, arg3, arg4) } + */ + static <A, B, C, D> PooledConsumer<D> obtainConsumer( + QuadConsumer<? super A, ? super B, ? super C, ? super D> function, + A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) { + return acquire(PooledLambdaImpl.sPool, + function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4); + } + + /** + * {@link PooledFunction} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 placeholder for a missing argument. Use {@link #__} to get one + * @return a {@link PooledFunction}, equivalent to lambda: + * {@code (arg4) -> function(arg1, arg2, arg3, arg4) } + */ + static <A, B, C, D, R> PooledFunction<D, R> obtainFunction( + QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function, + A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) { + return acquire(PooledLambdaImpl.sPool, + function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4); + } + + /** + * Factory of {@link Message}s that contain an + * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its + * {@link Message#getCallback internal callback}. + * + * The callback is equivalent to one obtainable via + * {@link #obtainRunnable(QuadConsumer, Object, Object, Object, Object)} + * + * Note that using this method with {@link android.os.Handler#handleMessage} + * is more efficient than the alternative of {@link android.os.Handler#post} + * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points + * when obtaining {@link Message} and {@link PooledRunnable} from pools separately + * + * You may optionally set a {@link Message#what} for the message if you want to be + * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise + * there's no need to do so + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4) } when handled + */ + static <A, B, C, D> Message obtainMessage( + QuadConsumer<? super A, ? super B, ? super C, ? super D> function, + A arg1, B arg2, C arg3, D arg4) { + synchronized (Message.sPoolSync) { + PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, + function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4); + return Message.obtain().setCallback(callback.recycleOnUse()); + } + } +} diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java new file mode 100755 index 000000000000..03e013cd46b8 --- /dev/null +++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java @@ -0,0 +1,557 @@ +/* + * Copyright (C) 2017 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.util.function.pooled; + +import android.annotation.Nullable; +import android.os.Message; +import android.text.TextUtils; +import android.util.Log; +import android.util.Pools; + +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.BitUtils; +import com.android.internal.util.function.QuadConsumer; +import com.android.internal.util.function.QuadFunction; +import com.android.internal.util.function.QuadPredicate; +import com.android.internal.util.function.TriConsumer; +import com.android.internal.util.function.TriFunction; +import com.android.internal.util.function.TriPredicate; + +import java.util.Arrays; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + +/** + * @see PooledLambda + * @hide + */ +final class PooledLambdaImpl<R> extends OmniFunction<Object, Object, Object, Object, R> { + + private static final boolean DEBUG = false; + private static final String LOG_TAG = "PooledLambdaImpl"; + + private static final int MAX_ARGS = 4; + + private static final int MAX_POOL_SIZE = 50; + + static class Pool extends Pools.SynchronizedPool<PooledLambdaImpl> { + + public Pool(Object lock) { + super(MAX_POOL_SIZE, lock); + } + } + + static final Pool sPool = new Pool(new Object()); + static final Pool sMessageCallbacksPool = new Pool(Message.sPoolSync); + + private PooledLambdaImpl() {} + + /** + * The function reference to be invoked + * + * May be the return value itself in case when an immediate result constant is provided instead + */ + Object mFunc; + + /** + * A primitive result value to be immediately returned on invocation instead of calling + * {@link #mFunc} + */ + long mConstValue; + + /** + * Arguments for {@link #mFunc} + */ + @Nullable Object[] mArgs = null; + + /** + * Flag for {@link #mFlags} + * + * Indicates whether this instance is recycled + */ + private static final int FLAG_RECYCLED = 1 << MAX_ARGS; + + /** + * Flag for {@link #mFlags} + * + * Indicates whether this instance should be immediately recycled on invocation + * (as requested via {@link PooledLambda#recycleOnUse()}) or not(default) + */ + private static final int FLAG_RECYCLE_ON_USE = 1 << (MAX_ARGS + 1); + + /** + * Flag for {@link #mFlags} + * + * Indicates that this instance was acquired from {@link #sMessageCallbacksPool} as opposed to + * {@link #sPool} + */ + private static final int FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL = 1 << (MAX_ARGS + 2); + + /** @see #mFlags */ + static final int MASK_EXPOSED_AS = LambdaType.MASK << (MAX_ARGS + 3); + + /** @see #mFlags */ + static final int MASK_FUNC_TYPE = LambdaType.MASK << + (MAX_ARGS + 3 + LambdaType.MASK_BIT_COUNT); + + /** + * Bit schema: + * AAAABCDEEEEEEFFFFFF + * + * Where: + * A - whether {@link #mArgs arg} at corresponding index was specified at + * {@link #acquire creation time} (0) or {@link #invoke invocation time} (1) + * B - {@link #FLAG_RECYCLED} + * C - {@link #FLAG_RECYCLE_ON_USE} + * D - {@link #FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL} + * E - {@link LambdaType} representing the type of the lambda returned to the caller from a + * factory method + * F - {@link LambdaType} of {@link #mFunc} as resolved when calling a factory method + */ + int mFlags = 0; + + + @Override + public void recycle() { + if (DEBUG) Log.i(LOG_TAG, this + ".recycle()"); + if (!isRecycled()) doRecycle(); + } + + private void doRecycle() { + if (DEBUG) Log.i(LOG_TAG, this + ".doRecycle()"); + Pool pool = (mFlags & FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL) != 0 + ? PooledLambdaImpl.sMessageCallbacksPool + : PooledLambdaImpl.sPool; + + mFunc = null; + if (mArgs != null) Arrays.fill(mArgs, null); + mFlags = FLAG_RECYCLED; + mConstValue = 0L; + + pool.release(this); + } + + @Override + R invoke(Object a1, Object a2, Object a3, Object a4) { + checkNotRecycled(); + if (DEBUG) { + Log.i(LOG_TAG, this + ".invoke(" + + commaSeparateFirstN( + new Object[] { a1, a2, a3, a4 }, + LambdaType.decodeArgCount(getFlags(MASK_EXPOSED_AS))) + + ")"); + } + boolean ignored = fillInArg(a1) && fillInArg(a2) && fillInArg(a3) && fillInArg(a4); + int argCount = LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE)); + if (argCount != LambdaType.MASK_ARG_COUNT) { + for (int i = 0; i < argCount; i++) { + if (mArgs[i] == ArgumentPlaceholder.INSTANCE) { + throw new IllegalStateException("Missing argument #" + i + " among " + + Arrays.toString(mArgs)); + } + } + } + try { + return doInvoke(); + } finally { + if (isRecycleOnUse()) doRecycle(); + if (!isRecycled()) { + int argsSize = ArrayUtils.size(mArgs); + for (int i = 0; i < argsSize; i++) { + popArg(i); + } + } + } + } + + private boolean fillInArg(Object invocationArg) { + int argsSize = ArrayUtils.size(mArgs); + for (int i = 0; i < argsSize; i++) { + if (mArgs[i] == ArgumentPlaceholder.INSTANCE) { + mArgs[i] = invocationArg; + mFlags |= BitUtils.bitAt(i); + return true; + } + } + if (invocationArg != null && invocationArg != ArgumentPlaceholder.INSTANCE) { + throw new IllegalStateException("No more arguments expected for provided arg " + + invocationArg + " among " + Arrays.toString(mArgs)); + } + return false; + } + + private void checkNotRecycled() { + if (isRecycled()) throw new IllegalStateException("Instance is recycled: " + this); + } + + @SuppressWarnings("unchecked") + private R doInvoke() { + final int funcType = getFlags(MASK_FUNC_TYPE); + final int argCount = LambdaType.decodeArgCount(funcType); + final int returnType = LambdaType.decodeReturnType(funcType); + + switch (argCount) { + case LambdaType.MASK_ARG_COUNT: { + switch (returnType) { + case LambdaType.ReturnType.INT: return (R) (Integer) getAsInt(); + case LambdaType.ReturnType.LONG: return (R) (Long) getAsLong(); + case LambdaType.ReturnType.DOUBLE: return (R) (Double) getAsDouble(); + default: return (R) mFunc; + } + } + case 0: { + switch (returnType) { + case LambdaType.ReturnType.VOID: { + ((Runnable) mFunc).run(); + return null; + } + case LambdaType.ReturnType.BOOLEAN: + case LambdaType.ReturnType.OBJECT: { + return (R) ((Supplier) mFunc).get(); + } + } + } break; + case 1: { + switch (returnType) { + case LambdaType.ReturnType.VOID: { + ((Consumer) mFunc).accept(popArg(0)); + return null; + } + case LambdaType.ReturnType.BOOLEAN: { + return (R) (Object) ((Predicate) mFunc).test(popArg(0)); + } + case LambdaType.ReturnType.OBJECT: { + return (R) ((Function) mFunc).apply(popArg(0)); + } + } + } break; + case 2: { + switch (returnType) { + case LambdaType.ReturnType.VOID: { + ((BiConsumer) mFunc).accept(popArg(0), popArg(1)); + return null; + } + case LambdaType.ReturnType.BOOLEAN: { + return (R) (Object) ((BiPredicate) mFunc).test(popArg(0), popArg(1)); + } + case LambdaType.ReturnType.OBJECT: { + return (R) ((BiFunction) mFunc).apply(popArg(0), popArg(1)); + } + } + } break; + case 3: { + switch (returnType) { + case LambdaType.ReturnType.VOID: { + ((TriConsumer) mFunc).accept(popArg(0), popArg(1), popArg(2)); + return null; + } + case LambdaType.ReturnType.BOOLEAN: { + return (R) (Object) ((TriPredicate) mFunc).test( + popArg(0), popArg(1), popArg(2)); + } + case LambdaType.ReturnType.OBJECT: { + return (R) ((TriFunction) mFunc).apply(popArg(0), popArg(1), popArg(2)); + } + } + } break; + case 4: { + switch (returnType) { + case LambdaType.ReturnType.VOID: { + ((QuadConsumer) mFunc).accept(popArg(0), popArg(1), popArg(2), popArg(3)); + return null; + } + case LambdaType.ReturnType.BOOLEAN: { + return (R) (Object) ((QuadPredicate) mFunc).test( + popArg(0), popArg(1), popArg(2), popArg(3)); + } + case LambdaType.ReturnType.OBJECT: { + return (R) ((QuadFunction) mFunc).apply( + popArg(0), popArg(1), popArg(2), popArg(3)); + } + } + } break; + } + throw new IllegalStateException("Unknown function type: " + LambdaType.toString(funcType)); + } + + private boolean isConstSupplier() { + return LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE)) == LambdaType.MASK_ARG_COUNT; + } + + private Object popArg(int index) { + Object result = mArgs[index]; + if (isInvocationArgAtIndex(index)) { + mArgs[index] = ArgumentPlaceholder.INSTANCE; + mFlags &= ~BitUtils.bitAt(index); + } + return result; + } + + @Override + public String toString() { + if (isRecycled()) return "<recycled PooledLambda@" + hashCodeHex(this) + ">"; + + StringBuilder sb = new StringBuilder(); + if (isConstSupplier()) { + sb.append(getFuncTypeAsString()).append("(").append(doInvoke()).append(")"); + } else { + if (mFunc instanceof PooledLambdaImpl) { + sb.append(mFunc); + } else { + sb.append(getFuncTypeAsString()).append("@").append(hashCodeHex(mFunc)); + } + sb.append("("); + sb.append(commaSeparateFirstN(mArgs, LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE)))); + sb.append(")"); + } + return sb.toString(); + } + + private String commaSeparateFirstN(@Nullable Object[] arr, int n) { + if (arr == null) return ""; + return TextUtils.join(",", Arrays.copyOf(arr, n)); + } + + private static String hashCodeHex(Object o) { + return Integer.toHexString(o.hashCode()); + } + + private String getFuncTypeAsString() { + if (isRecycled()) throw new IllegalStateException(); + if (isConstSupplier()) return "supplier"; + String name = LambdaType.toString(getFlags(MASK_EXPOSED_AS)); + if (name.endsWith("Consumer")) return "consumer"; + if (name.endsWith("Function")) return "function"; + if (name.endsWith("Predicate")) return "predicate"; + if (name.endsWith("Supplier")) return "supplier"; + if (name.endsWith("Runnable")) return "runnable"; + throw new IllegalStateException("Don't know the string representation of " + name); + } + + /** + * Internal non-typesafe factory method for {@link PooledLambdaImpl} + */ + static <E extends PooledLambda> E acquire(Pool pool, Object f, + int fNumArgs, int numPlaceholders, int fReturnType, + Object a, Object b, Object c, Object d) { + PooledLambdaImpl r = acquire(pool); + if (DEBUG) { + Log.i(LOG_TAG, + "acquire(this = @" + hashCodeHex(r) + + ", f = " + f + + ", fNumArgs = " + fNumArgs + + ", numPlaceholders = " + numPlaceholders + + ", fReturnType = " + LambdaType.ReturnType.toString(fReturnType) + + ", a = " + a + + ", b = " + b + + ", c = " + c + + ", d = " + d + + ")"); + } + r.mFunc = f; + r.setFlags(MASK_FUNC_TYPE, LambdaType.encode(fNumArgs, fReturnType)); + r.setFlags(MASK_EXPOSED_AS, LambdaType.encode(numPlaceholders, fReturnType)); + if (ArrayUtils.size(r.mArgs) < fNumArgs) r.mArgs = new Object[fNumArgs]; + setIfInBounds(r.mArgs, 0, a); + setIfInBounds(r.mArgs, 1, b); + setIfInBounds(r.mArgs, 2, c); + setIfInBounds(r.mArgs, 3, d); + return (E) r; + } + + static PooledLambdaImpl acquireConstSupplier(int type) { + PooledLambdaImpl r = acquire(PooledLambdaImpl.sPool); + int lambdaType = LambdaType.encode(LambdaType.MASK_ARG_COUNT, type); + r.setFlags(PooledLambdaImpl.MASK_FUNC_TYPE, lambdaType); + r.setFlags(PooledLambdaImpl.MASK_EXPOSED_AS, lambdaType); + return r; + } + + static PooledLambdaImpl acquire(Pool pool) { + PooledLambdaImpl r = pool.acquire(); + if (r == null) r = new PooledLambdaImpl(); + r.mFlags &= ~FLAG_RECYCLED; + r.setFlags(FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL, + pool == sMessageCallbacksPool ? 1 : 0); + return r; + } + + private static void setIfInBounds(Object[] array, int i, Object a) { + if (i < ArrayUtils.size(array)) array[i] = a; + } + + @Override + public OmniFunction<Object, Object, Object, Object, R> negate() { + throw new UnsupportedOperationException(); + } + + @Override + public <V> OmniFunction<Object, Object, Object, Object, V> andThen( + Function<? super R, ? extends V> after) { + throw new UnsupportedOperationException(); + } + + @Override + public double getAsDouble() { + return Double.longBitsToDouble(mConstValue); + } + + @Override + public int getAsInt() { + return (int) mConstValue; + } + + @Override + public long getAsLong() { + return mConstValue; + } + + @Override + public OmniFunction<Object, Object, Object, Object, R> recycleOnUse() { + if (DEBUG) Log.i(LOG_TAG, this + ".recycleOnUse()"); + mFlags |= FLAG_RECYCLE_ON_USE; + return this; + } + + private boolean isRecycled() { + return (mFlags & FLAG_RECYCLED) != 0; + } + + private boolean isRecycleOnUse() { + return (mFlags & FLAG_RECYCLE_ON_USE) != 0; + } + + private boolean isInvocationArgAtIndex(int argIndex) { + return (mFlags & (1 << argIndex)) != 0; + } + + int getFlags(int mask) { + return unmask(mask, mFlags); + } + + void setFlags(int mask, int value) { + mFlags &= ~mask; + mFlags |= mask(mask, value); + } + + /** + * 0xFF000, 0xAB -> 0xAB000 + */ + private static int mask(int mask, int value) { + return (value << Integer.numberOfTrailingZeros(mask)) & mask; + } + + /** + * 0xFF000, 0xAB123 -> 0xAB + */ + private static int unmask(int mask, int bits) { + return (bits & mask) / (1 << Integer.numberOfTrailingZeros(mask)); + } + + /** + * Contract for encoding a supported lambda type in {@link #MASK_BIT_COUNT} bits + */ + static class LambdaType { + public static final int MASK_ARG_COUNT = 0b111; + public static final int MASK_RETURN_TYPE = 0b111000; + public static final int MASK = MASK_ARG_COUNT | MASK_RETURN_TYPE; + public static final int MASK_BIT_COUNT = 6; + + static int encode(int argCount, int returnType) { + return mask(MASK_ARG_COUNT, argCount) | mask(MASK_RETURN_TYPE, returnType); + } + + static int decodeArgCount(int type) { + return type & MASK_ARG_COUNT; + } + + static int decodeReturnType(int type) { + return unmask(MASK_RETURN_TYPE, type); + } + + static String toString(int type) { + int argCount = decodeArgCount(type); + int returnType = decodeReturnType(type); + if (argCount == 0) { + if (returnType == ReturnType.VOID) return "Runnable"; + if (returnType == ReturnType.OBJECT || returnType == ReturnType.BOOLEAN) { + return "Supplier"; + } + } + return argCountPrefix(argCount) + ReturnType.lambdaSuffix(returnType); + } + + private static String argCountPrefix(int argCount) { + switch (argCount) { + case MASK_ARG_COUNT: return ""; + case 1: return ""; + case 2: return "Bi"; + case 3: return "Tri"; + case 4: return "Quad"; + default: throw new IllegalArgumentException("" + argCount); + } + } + + static class ReturnType { + public static final int VOID = 1; + public static final int BOOLEAN = 2; + public static final int OBJECT = 3; + public static final int INT = 4; + public static final int LONG = 5; + public static final int DOUBLE = 6; + + static String toString(int returnType) { + switch (returnType) { + case VOID: return "VOID"; + case BOOLEAN: return "BOOLEAN"; + case OBJECT: return "OBJECT"; + case INT: return "INT"; + case LONG: return "LONG"; + case DOUBLE: return "DOUBLE"; + default: return "" + returnType; + } + } + + static String lambdaSuffix(int type) { + return prefix(type) + suffix(type); + } + + private static String prefix(int type) { + switch (type) { + case INT: return "Int"; + case LONG: return "Long"; + case DOUBLE: return "Double"; + default: return ""; + } + } + + private static String suffix(int type) { + switch (type) { + case VOID: return "Consumer"; + case BOOLEAN: return "Predicate"; + case OBJECT: return "Function"; + default: return "Supplier"; + } + } + } + } +} diff --git a/core/java/com/android/internal/util/function/pooled/PooledPredicate.java b/core/java/com/android/internal/util/function/pooled/PooledPredicate.java new file mode 100644 index 000000000000..9b14366452e5 --- /dev/null +++ b/core/java/com/android/internal/util/function/pooled/PooledPredicate.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 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.util.function.pooled; + +import java.util.function.Predicate; + +/** + * {@link Predicate} + {@link PooledLambda} + * + * @see PooledLambda + * @hide + */ +public interface PooledPredicate<T> extends PooledLambda, Predicate<T> { + + /** + * Ignores the result + */ + PooledConsumer<T> asConsumer(); + + /** @inheritDoc */ + PooledPredicate<T> recycleOnUse(); +} diff --git a/core/java/com/android/internal/util/function/pooled/PooledRunnable.java b/core/java/com/android/internal/util/function/pooled/PooledRunnable.java new file mode 100644 index 000000000000..89ca82e2f3ce --- /dev/null +++ b/core/java/com/android/internal/util/function/pooled/PooledRunnable.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2017 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.util.function.pooled; + +import com.android.internal.util.FunctionalUtils.ThrowingRunnable; + +/** + * {@link Runnable} + {@link PooledLambda} + * + * @see PooledLambda + * @hide + */ +public interface PooledRunnable extends PooledLambda, Runnable, ThrowingRunnable { + /** @inheritDoc */ + PooledRunnable recycleOnUse(); +} diff --git a/core/java/com/android/internal/util/function/pooled/PooledSupplier.java b/core/java/com/android/internal/util/function/pooled/PooledSupplier.java new file mode 100644 index 000000000000..dd7f73eeff14 --- /dev/null +++ b/core/java/com/android/internal/util/function/pooled/PooledSupplier.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2017 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.util.function.pooled; + +import com.android.internal.util.FunctionalUtils.ThrowingSupplier; + +import java.util.function.DoubleSupplier; +import java.util.function.IntSupplier; +import java.util.function.LongSupplier; +import java.util.function.Supplier; + +/** + * {@link Supplier} + {@link PooledLambda} + * + * @see PooledLambda + * @hide + */ +public interface PooledSupplier<T> extends PooledLambda, Supplier<T>, ThrowingSupplier<T> { + + /** + * Ignores the result + */ + PooledRunnable asRunnable(); + + /** @inheritDoc */ + PooledSupplier<T> recycleOnUse(); + + /** {@link PooledLambda} + {@link IntSupplier} */ + interface OfInt extends IntSupplier, PooledLambda { + /** @inheritDoc */ + PooledSupplier.OfInt recycleOnUse(); + } + + /** {@link PooledLambda} + {@link LongSupplier} */ + interface OfLong extends LongSupplier, PooledLambda { + /** @inheritDoc */ + PooledSupplier.OfLong recycleOnUse(); + } + + /** {@link PooledLambda} + {@link DoubleSupplier} */ + interface OfDouble extends DoubleSupplier, PooledLambda { + /** @inheritDoc */ + PooledSupplier.OfDouble recycleOnUse(); + } +} diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index f2f01cfa19b0..d44fe4dbc450 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -21,6 +21,7 @@ import static com.android.internal.util.CollectionUtils.size; import static com.android.internal.util.Preconditions.checkArgument; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.internal.util.Preconditions.checkState; +import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable; import android.Manifest; import android.annotation.CheckResult; @@ -69,6 +70,7 @@ import com.android.internal.content.PackageMonitor; import com.android.internal.notification.NotificationAccessConfirmationActivityContract; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; +import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.FgThread; import com.android.server.SystemService; @@ -440,32 +442,35 @@ public class CompanionDeviceManagerService extends SystemService implements Bind return; } - Binder.withCleanCallingIdentity(() -> { - try { - if (containsEither(packageInfo.requestedPermissions, - Manifest.permission.RUN_IN_BACKGROUND, - Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND)) { - mIdleController.addPowerSaveWhitelistApp(packageInfo.packageName); - } else { - mIdleController.removePowerSaveWhitelistApp(packageInfo.packageName); - } - } catch (RemoteException e) { - /* ignore - local call */ - } + Binder.withCleanCallingIdentity(obtainRunnable(CompanionDeviceManagerService:: + updateSpecialAccessPermissionAsSystem, this, packageInfo).recycleOnUse()); + } - NetworkPolicyManager networkPolicyManager = NetworkPolicyManager.from(getContext()); + private void updateSpecialAccessPermissionAsSystem(PackageInfo packageInfo) { + try { if (containsEither(packageInfo.requestedPermissions, - Manifest.permission.USE_DATA_IN_BACKGROUND, - Manifest.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND)) { - networkPolicyManager.addUidPolicy( - packageInfo.applicationInfo.uid, - NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND); + android.Manifest.permission.RUN_IN_BACKGROUND, + android.Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND)) { + mIdleController.addPowerSaveWhitelistApp(packageInfo.packageName); } else { - networkPolicyManager.removeUidPolicy( - packageInfo.applicationInfo.uid, - NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND); + mIdleController.removePowerSaveWhitelistApp(packageInfo.packageName); } - }); + } catch (RemoteException e) { + /* ignore - local call */ + } + + NetworkPolicyManager networkPolicyManager = NetworkPolicyManager.from(getContext()); + if (containsEither(packageInfo.requestedPermissions, + android.Manifest.permission.USE_DATA_IN_BACKGROUND, + android.Manifest.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND)) { + networkPolicyManager.addUidPolicy( + packageInfo.applicationInfo.uid, + NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND); + } else { + networkPolicyManager.removeUidPolicy( + packageInfo.applicationInfo.uid, + NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND); + } } private static <T> boolean containsEither(T[] array, T a, T b) { @@ -474,17 +479,17 @@ public class CompanionDeviceManagerService extends SystemService implements Bind @Nullable private PackageInfo getPackageInfo(String packageName, int userId) { - return Binder.withCleanCallingIdentity(() -> { + return Binder.withCleanCallingIdentity(PooledLambda.obtainSupplier((context, pkg, id) -> { try { - return getContext().getPackageManager().getPackageInfoAsUser( - packageName, + return context.getPackageManager().getPackageInfoAsUser( + pkg, PackageManager.GET_PERMISSIONS | PackageManager.GET_CONFIGURATIONS, - userId); + id); } catch (PackageManager.NameNotFoundException e) { - Slog.e(LOG_TAG, "Failed to get PackageInfo for package " + packageName, e); + Slog.e(LOG_TAG, "Failed to get PackageInfo for package " + pkg, e); return null; } - }); + }, getContext(), packageName, userId).recycleOnUse()); } private void recordAssociation(String priviledgedPackage, String deviceAddress) { diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java index e8ae020c2728..364bbc035a29 100644 --- a/services/print/java/com/android/server/print/UserState.java +++ b/services/print/java/com/android/server/print/UserState.java @@ -25,6 +25,7 @@ import static com.android.internal.print.DumpUtils.writePrintJobInfo; import static com.android.internal.print.DumpUtils.writePrinterId; import static com.android.internal.print.DumpUtils.writePrinterInfo; import static com.android.internal.print.DumpUtils.writeStringIfNotNull; +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import android.annotation.NonNull; import android.annotation.Nullable; @@ -81,7 +82,6 @@ import com.android.internal.R; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.os.BackgroundThread; -import com.android.internal.os.SomeArgs; import com.android.server.print.RemotePrintService.PrintServiceCallbacks; import com.android.server.print.RemotePrintServiceRecommendationService .RemotePrintServiceRecommendationServiceCallbacks; @@ -462,7 +462,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, if (mPrinterDiscoverySession == null) { // If we do not have a session, tell all service to create one. - mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) { + mPrinterDiscoverySession = new PrinterDiscoverySessionMediator() { @Override public void onDestroyed() { mPrinterDiscoverySession = null; @@ -1141,12 +1141,8 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, // just died. Do this off the main thread since we do to allow // calls into the spooler on the main thread. if (Looper.getMainLooper().isCurrentThread()) { - BackgroundThread.getHandler().post(new Runnable() { - @Override - public void run() { - failScheduledPrintJobsForServiceInternal(serviceName); - } - }); + BackgroundThread.getHandler().sendMessage(obtainMessage( + UserState::failScheduledPrintJobsForServiceInternal, this, serviceName)); } else { failScheduledPrintJobsForServiceInternal(serviceName); } @@ -1341,18 +1337,13 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, private final List<PrinterId> mStateTrackedPrinters = new ArrayList<PrinterId>(); - private final Handler mSessionHandler; - private boolean mIsDestroyed; - public PrinterDiscoverySessionMediator(Context context) { - mSessionHandler = new SessionHandler(context.getMainLooper()); + PrinterDiscoverySessionMediator() { // Kick off the session creation. - List<RemotePrintService> services = new ArrayList<RemotePrintService>( - mActiveServices.values()); - mSessionHandler.obtainMessage(SessionHandler - .MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION, services) - .sendToTarget(); + Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator:: + handleDispatchCreatePrinterDiscoverySession, + this, new ArrayList<>(mActiveServices.values()))); } public void addObserverLocked(@NonNull IPrinterDiscoveryObserver observer) { @@ -1361,12 +1352,9 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, // Bring the added observer up to speed with the printers. if (!mPrinters.isEmpty()) { - List<PrinterInfo> printers = new ArrayList<PrinterInfo>(mPrinters.values()); - SomeArgs args = SomeArgs.obtain(); - args.arg1 = observer; - args.arg2 = printers; - mSessionHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED, - args).sendToTarget(); + Handler.getMain().sendMessage(obtainMessage( + UserState.PrinterDiscoverySessionMediator::handlePrintersAdded, + this, observer, new ArrayList<>(mPrinters.values()))); } } @@ -1403,14 +1391,9 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, return; } - List<RemotePrintService> services = new ArrayList<RemotePrintService>( - mActiveServices.values()); - SomeArgs args = SomeArgs.obtain(); - args.arg1 = services; - args.arg2 = priorityList; - mSessionHandler.obtainMessage(SessionHandler - .MSG_DISPATCH_START_PRINTER_DISCOVERY, args) - .sendToTarget(); + Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator:: + handleDispatchStartPrinterDiscovery, this, + new ArrayList<>(mActiveServices.values()), priorityList)); } public final void stopPrinterDiscoveryLocked(@NonNull IPrinterDiscoveryObserver observer) { @@ -1426,11 +1409,9 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, if (!mStartedPrinterDiscoveryTokens.isEmpty()) { return; } - List<RemotePrintService> services = new ArrayList<RemotePrintService>( - mActiveServices.values()); - mSessionHandler.obtainMessage(SessionHandler - .MSG_DISPATCH_STOP_PRINTER_DISCOVERY, services) - .sendToTarget(); + Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator:: + handleDispatchStopPrinterDiscovery, + this, new ArrayList<>(mActiveServices.values()))); } public void validatePrintersLocked(@NonNull List<PrinterId> printerIds) { @@ -1461,12 +1442,9 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, // Schedule a notification of the service. RemotePrintService service = mActiveServices.get(serviceName); if (service != null) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = service; - args.arg2 = updateList; - mSessionHandler.obtainMessage(SessionHandler - .MSG_VALIDATE_PRINTERS, args) - .sendToTarget(); + Handler.getMain().sendMessage(obtainMessage( + UserState.PrinterDiscoverySessionMediator::handleValidatePrinters, + this, service, updateList)); } } } @@ -1493,12 +1471,8 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, return; } // Ask the service to start tracking. - SomeArgs args = SomeArgs.obtain(); - args.arg1 = service; - args.arg2 = printerId; - mSessionHandler.obtainMessage(SessionHandler - .MSG_START_PRINTER_STATE_TRACKING, args) - .sendToTarget(); + Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator:: + handleStartPrinterStateTracking, this, service, printerId)); } public final void stopPrinterStateTrackingLocked(PrinterId printerId) { @@ -1520,12 +1494,8 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, return; } // Ask the service to start tracking. - SomeArgs args = SomeArgs.obtain(); - args.arg1 = service; - args.arg2 = printerId; - mSessionHandler.obtainMessage(SessionHandler - .MSG_STOP_PRINTER_STATE_TRACKING, args) - .sendToTarget(); + Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator:: + handleStopPrinterStateTracking, this, service, printerId)); } public void onDestroyed() { @@ -1551,11 +1521,9 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver.Stub.asInterface(token)); } // Tell the services we are done. - List<RemotePrintService> services = new ArrayList<RemotePrintService>( - mActiveServices.values()); - mSessionHandler.obtainMessage(SessionHandler - .MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION, services) - .sendToTarget(); + Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator:: + handleDispatchDestroyPrinterDiscoverySession, + this, new ArrayList<>(mActiveServices.values()))); } public void onPrintersAddedLocked(List<PrinterInfo> printers) { @@ -1579,8 +1547,9 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, } } if (addedPrinters != null) { - mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED, - addedPrinters).sendToTarget(); + Handler.getMain().sendMessage(obtainMessage( + UserState.PrinterDiscoverySessionMediator::handleDispatchPrintersAdded, + this, addedPrinters)); } } @@ -1604,8 +1573,9 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, } } if (removedPrinterIds != null) { - mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED, - removedPrinterIds).sendToTarget(); + Handler.getMain().sendMessage(obtainMessage( + UserState.PrinterDiscoverySessionMediator::handleDispatchPrintersRemoved, + this, removedPrinterIds)); } } @@ -1646,8 +1616,9 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, ArrayList<PrinterInfo> addedPrinters = new ArrayList<>(1); addedPrinters.add(newPrinter); - mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED, - addedPrinters).sendToTarget(); + Handler.getMain().sendMessage(obtainMessage( + UserState.PrinterDiscoverySessionMediator::handleDispatchPrintersAdded, + this, addedPrinters)); } } @@ -1661,26 +1632,20 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, return; } // Tell the service to create a session. - mSessionHandler.obtainMessage( - SessionHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION, - service).sendToTarget(); + Handler.getMain().sendMessage(obtainMessage( + RemotePrintService::createPrinterDiscoverySession, service)); // Start printer discovery if necessary. if (!mStartedPrinterDiscoveryTokens.isEmpty()) { - mSessionHandler.obtainMessage( - SessionHandler.MSG_START_PRINTER_DISCOVERY, - service).sendToTarget(); + Handler.getMain().sendMessage(obtainMessage( + RemotePrintService::startPrinterDiscovery, service, null)); } // Start tracking printers if necessary final int trackedPrinterCount = mStateTrackedPrinters.size(); for (int i = 0; i < trackedPrinterCount; i++) { PrinterId printerId = mStateTrackedPrinters.get(i); if (printerId.getServiceName().equals(service.getComponentName())) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = service; - args.arg2 = printerId; - mSessionHandler.obtainMessage(SessionHandler - .MSG_START_PRINTER_STATE_TRACKING, args) - .sendToTarget(); + Handler.getMain().sendMessage(obtainMessage( + RemotePrintService::startPrinterStateTracking, service, printerId)); } } } @@ -1781,9 +1746,9 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, for (int i = 0; i < removedPrinterCount; i++) { mPrinters.remove(removedPrinterIds.get(i)); } - mSessionHandler.obtainMessage( - SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED, - removedPrinterIds).sendToTarget(); + Handler.getMain().sendMessage(obtainMessage( + UserState.PrinterDiscoverySessionMediator::handleDispatchPrintersRemoved, + this, removedPrinterIds)); } } @@ -1873,134 +1838,6 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, Log.e(LOG_TAG, "Error sending removed printers", re); } } - - private final class SessionHandler extends Handler { - public static final int MSG_PRINTERS_ADDED = 1; - public static final int MSG_PRINTERS_REMOVED = 2; - public static final int MSG_DISPATCH_PRINTERS_ADDED = 3; - public static final int MSG_DISPATCH_PRINTERS_REMOVED = 4; - - public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 5; - public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 6; - public static final int MSG_START_PRINTER_DISCOVERY = 7; - public static final int MSG_STOP_PRINTER_DISCOVERY = 8; - public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 9; - public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 10; - public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 11; - public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 12; - public static final int MSG_VALIDATE_PRINTERS = 13; - public static final int MSG_START_PRINTER_STATE_TRACKING = 14; - public static final int MSG_STOP_PRINTER_STATE_TRACKING = 15; - public static final int MSG_DESTROY_SERVICE = 16; - - SessionHandler(Looper looper) { - super(looper, null, false); - } - - @Override - @SuppressWarnings("unchecked") - public void handleMessage(Message message) { - switch (message.what) { - case MSG_PRINTERS_ADDED: { - SomeArgs args = (SomeArgs) message.obj; - IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1; - List<PrinterInfo> addedPrinters = (List<PrinterInfo>) args.arg2; - args.recycle(); - handlePrintersAdded(observer, addedPrinters); - } break; - - case MSG_PRINTERS_REMOVED: { - SomeArgs args = (SomeArgs) message.obj; - IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1; - List<PrinterId> removedPrinterIds = (List<PrinterId>) args.arg2; - args.recycle(); - handlePrintersRemoved(observer, removedPrinterIds); - } - - case MSG_DISPATCH_PRINTERS_ADDED: { - List<PrinterInfo> addedPrinters = (List<PrinterInfo>) message.obj; - handleDispatchPrintersAdded(addedPrinters); - } break; - - case MSG_DISPATCH_PRINTERS_REMOVED: { - List<PrinterId> removedPrinterIds = (List<PrinterId>) message.obj; - handleDispatchPrintersRemoved(removedPrinterIds); - } break; - - case MSG_CREATE_PRINTER_DISCOVERY_SESSION: { - RemotePrintService service = (RemotePrintService) message.obj; - service.createPrinterDiscoverySession(); - } break; - - case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: { - RemotePrintService service = (RemotePrintService) message.obj; - service.destroyPrinterDiscoverySession(); - } break; - - case MSG_START_PRINTER_DISCOVERY: { - RemotePrintService service = (RemotePrintService) message.obj; - service.startPrinterDiscovery(null); - } break; - - case MSG_STOP_PRINTER_DISCOVERY: { - RemotePrintService service = (RemotePrintService) message.obj; - service.stopPrinterDiscovery(); - } break; - - case MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION: { - List<RemotePrintService> services = (List<RemotePrintService>) message.obj; - handleDispatchCreatePrinterDiscoverySession(services); - } break; - - case MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION: { - List<RemotePrintService> services = (List<RemotePrintService>) message.obj; - handleDispatchDestroyPrinterDiscoverySession(services); - } break; - - case MSG_DISPATCH_START_PRINTER_DISCOVERY: { - SomeArgs args = (SomeArgs) message.obj; - List<RemotePrintService> services = (List<RemotePrintService>) args.arg1; - List<PrinterId> printerIds = (List<PrinterId>) args.arg2; - args.recycle(); - handleDispatchStartPrinterDiscovery(services, printerIds); - } break; - - case MSG_DISPATCH_STOP_PRINTER_DISCOVERY: { - List<RemotePrintService> services = (List<RemotePrintService>) message.obj; - handleDispatchStopPrinterDiscovery(services); - } break; - - case MSG_VALIDATE_PRINTERS: { - SomeArgs args = (SomeArgs) message.obj; - RemotePrintService service = (RemotePrintService) args.arg1; - List<PrinterId> printerIds = (List<PrinterId>) args.arg2; - args.recycle(); - handleValidatePrinters(service, printerIds); - } break; - - case MSG_START_PRINTER_STATE_TRACKING: { - SomeArgs args = (SomeArgs) message.obj; - RemotePrintService service = (RemotePrintService) args.arg1; - PrinterId printerId = (PrinterId) args.arg2; - args.recycle(); - handleStartPrinterStateTracking(service, printerId); - } break; - - case MSG_STOP_PRINTER_STATE_TRACKING: { - SomeArgs args = (SomeArgs) message.obj; - RemotePrintService service = (RemotePrintService) args.arg1; - PrinterId printerId = (PrinterId) args.arg2; - args.recycle(); - handleStopPrinterStateTracking(service, printerId); - } break; - - case MSG_DESTROY_SERVICE: { - RemotePrintService service = (RemotePrintService) message.obj; - service.destroy(); - } break; - } - } - } } private final class PrintJobForAppCache { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 7e11e87b9f22..e2ba4d5f4aa8 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -103,7 +103,7 @@ public class DpmMockContext extends MockContext { long callingIdentity = clearCallingIdentity(); Throwable throwableToPropagate = null; try { - action.run(); + action.runOrThrow(); } catch (Throwable throwable) { throwableToPropagate = throwable; } finally { |