| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package com.android.webview.chromium; |
| |
| import android.os.Build; |
| |
| import androidx.annotation.NonNull; |
| import androidx.annotation.Nullable; |
| |
| import org.chromium.support_lib_boundary.ProcessGlobalConfigConstants; |
| |
| import java.lang.reflect.Field; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.concurrent.atomic.AtomicReference; |
| |
| /** |
| * Class that contains the process global configuration information if it was set by the embedding |
| * app using androidx.webkit.ProcessGlobalConfig. |
| */ |
| public final class AndroidXProcessGlobalConfig { |
| private String mDataDirectorySuffix; |
| private String mDataDirectoryBasePath; |
| private String mCacheDirectoryBasePath; |
| private static AndroidXProcessGlobalConfig sGlobalConfig; |
| |
| private AndroidXProcessGlobalConfig(@NonNull Map<String, Object> configMap) { |
| for (Entry<String, Object> entry : configMap.entrySet()) { |
| Object configValue = entry.getValue(); |
| switch (entry.getKey()) { |
| case ProcessGlobalConfigConstants.DATA_DIRECTORY_SUFFIX: |
| if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { |
| throw new RuntimeException( |
| "AndroidXProcessGlobalConfig map should not have value set for " |
| + "key: " + entry.getKey() |
| + " in SDK version >= " + Build.VERSION_CODES.P); |
| } |
| if (!(configValue instanceof String)) { |
| throw new RuntimeException("AndroidXProcessGlobalConfig map does not have " |
| + "right type of value for key: " + entry.getKey()); |
| } |
| mDataDirectorySuffix = (String) configValue; |
| break; |
| case ProcessGlobalConfigConstants.DATA_DIRECTORY_BASE_PATH: |
| if (!(configValue instanceof String)) { |
| throw new RuntimeException("AndroidXProcessGlobalConfig map does not have " |
| + "right type of value for key: " + entry.getKey()); |
| } |
| mDataDirectoryBasePath = (String) configValue; |
| break; |
| case ProcessGlobalConfigConstants.CACHE_DIRECTORY_BASE_PATH: |
| if (!(configValue instanceof String)) { |
| throw new RuntimeException("AndroidXProcessGlobalConfig map does not have " |
| + "right type of value for key: " + entry.getKey()); |
| } |
| mCacheDirectoryBasePath = (String) configValue; |
| break; |
| default: |
| throw new RuntimeException( |
| "AndroidXProcessGlobalConfig map contains unknown key: " |
| + entry.getKey()); |
| } |
| } |
| } |
| |
| /** |
| * Extracts the process global config that was set by the app in |
| * androidx.webkit.ProcessGlobalConfig. |
| * <p> |
| * This method should only be called once. |
| */ |
| public static void extractConfigFromApp(ClassLoader cl) { |
| assert sGlobalConfig == null; |
| HashMap<String, Object> configMap = null; |
| try { |
| Class<?> holder = Class.forName("androidx.webkit.ProcessGlobalConfig", true, cl); |
| Field sProcessGlobalConfig = holder.getDeclaredField("sProcessGlobalConfig"); |
| sProcessGlobalConfig.setAccessible(true); |
| AtomicReference<HashMap<String, Object>> configRef = |
| (AtomicReference<HashMap<String, Object>>) sProcessGlobalConfig.get(null); |
| configMap = configRef.get(); |
| } catch (Exception e) { |
| // The class probably doesn't exist - the app may not be using the AndroidX library, |
| // or not a recent enough version. |
| } |
| if (configMap == null) { |
| sGlobalConfig = new AndroidXProcessGlobalConfig(Collections.emptyMap()); |
| } else { |
| sGlobalConfig = new AndroidXProcessGlobalConfig(configMap); |
| } |
| } |
| |
| /** |
| * Gets the process global config that was set by the app in |
| * androidx.webkit.ProcessGlobalConfig. |
| * <p> |
| * This method should be called after calling {@link #extractConfigFromApp(ClassLoader)} |
| */ |
| public static @NonNull AndroidXProcessGlobalConfig getConfig() { |
| assert sGlobalConfig != null; |
| return sGlobalConfig; |
| } |
| |
| public @Nullable String getDataDirectorySuffixOrNull() { |
| return mDataDirectorySuffix; |
| } |
| |
| public @Nullable String getDataDirectoryBasePathOrNull() { |
| return mDataDirectoryBasePath; |
| } |
| |
| public @Nullable String getCacheDirectoryBasePathOrNull() { |
| return mCacheDirectoryBasePath; |
| } |
| } |