|  | // Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | package com.android.tools.r8.threading; | 
|  |  | 
|  | import com.android.tools.r8.errors.CompilationError; | 
|  | import com.android.tools.r8.keepanno.annotations.KeepConstraint; | 
|  | import com.android.tools.r8.keepanno.annotations.KeepItemKind; | 
|  | import com.android.tools.r8.keepanno.annotations.KeepTarget; | 
|  | import com.android.tools.r8.keepanno.annotations.MemberAccessFlags; | 
|  | import com.android.tools.r8.keepanno.annotations.UsedByReflection; | 
|  | import com.android.tools.r8.keepanno.annotations.UsesReflection; | 
|  | import com.google.common.collect.ImmutableList; | 
|  | import java.util.List; | 
|  | import java.util.concurrent.Callable; | 
|  | import java.util.concurrent.ExecutionException; | 
|  | import java.util.concurrent.ExecutorService; | 
|  | import java.util.concurrent.Future; | 
|  |  | 
|  | /** | 
|  | * Threading module interface to enable non-blocking usage of R8. | 
|  | * | 
|  | * <p>The threading module has multiple implementations outside the main R8 jar. The concrete | 
|  | * implementations are loaded via reflection. Since these implementations are dynamically loaded the | 
|  | * interface they implement must be kept. | 
|  | */ | 
|  | @UsedByReflection( | 
|  | description = "Implementations of this interface are dynamically loaded at runtime", | 
|  | kind = KeepItemKind.CLASS_AND_MEMBERS, | 
|  | memberAccess = {MemberAccessFlags.PUBLIC}) | 
|  | public interface ThreadingModule { | 
|  |  | 
|  | ExecutorService createSingleThreadedExecutorService(); | 
|  |  | 
|  | ExecutorService createThreadedExecutorService(int threadCount); | 
|  |  | 
|  | <T> Future<T> submit(Callable<T> task, ExecutorService executorService) throws ExecutionException; | 
|  |  | 
|  | <T> void awaitFutures(List<Future<T>> futures) throws ExecutionException; | 
|  |  | 
|  | class Loader { | 
|  |  | 
|  | @UsedByReflection( | 
|  | description = "Prevent analysis any inlining and assumptions of the provider class names", | 
|  | constraints = {KeepConstraint.NEVER_INLINE}) | 
|  | private static List<String> getProviderNames() { | 
|  | return ImmutableList.of( | 
|  | "com.android.tools.r8.threading.providers.blocking.ThreadingModuleBlockingProvider", | 
|  | "com.android.tools.r8.threading.providers.singlethreaded.ThreadingModuleSingleThreadedProvider"); | 
|  | } | 
|  |  | 
|  | @UsesReflection({ | 
|  | @KeepTarget( | 
|  | kind = KeepItemKind.CLASS_AND_METHODS, | 
|  | className = | 
|  | "com.android.tools.r8.threading.providers." | 
|  | + "blocking.ThreadingModuleBlockingProvider", | 
|  | methodName = "<init>", | 
|  | methodParameters = {}), | 
|  | @KeepTarget( | 
|  | kind = KeepItemKind.CLASS_AND_METHODS, | 
|  | className = | 
|  | "com.android.tools.r8.threading.providers." | 
|  | + "singlethreaded.ThreadingModuleSingleThreadedProvider", | 
|  | methodName = "<init>", | 
|  | methodParameters = {}) | 
|  | }) | 
|  | public static ThreadingModuleProvider load() { | 
|  | for (String name : getProviderNames()) { | 
|  | try { | 
|  | Class<?> providerClass = Class.forName(name); | 
|  | return (ThreadingModuleProvider) providerClass.getDeclaredConstructor().newInstance(); | 
|  | } catch (ClassNotFoundException ignored) { | 
|  | continue; | 
|  | } catch (ReflectiveOperationException e) { | 
|  | throw new CompilationError("Failure creating provider for the threading module", e); | 
|  | } | 
|  | } | 
|  | throw new CompilationError("Failure to find a provider for the threading module"); | 
|  | } | 
|  | } | 
|  | } |