1 // Copyright 2022 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.net.impl; 6 7 import android.content.ComponentName; 8 import android.content.Context; 9 import android.content.pm.PackageManager; 10 import android.content.pm.ServiceInfo; 11 import android.os.Bundle; 12 13 import androidx.annotation.VisibleForTesting; 14 15 import org.chromium.net.impl.CronetLogger.CronetSource; 16 17 /** 18 * Utilities for working with Cronet Android manifest flags. 19 * 20 * Cronet manifest flags must be defined within a service definition named after {@link 21 * #META_DATA_HOLDER_SERVICE_NAME} (the reason this is not defined at the application level is to 22 * avoid scalability issues with PackageManager queries). For example, to enable telemetry, add the 23 * following to {@code AndroidManifest.xml}: 24 * 25 * <pre>{@code 26 * <manifest ...> 27 * ... 28 * <application ...> 29 * ... 30 * <service android:name="android.net.http.MetaDataHolder" 31 * android:enabled="false" android:exported="false"> 32 * <meta-data android:name="android.net.http.EnableTelemetry" 33 * android:value="true" /> 34 * </service> 35 * </application> 36 * </manifest> 37 * }</pre> 38 */ 39 @VisibleForTesting 40 public final class CronetManifest { CronetManifest()41 private CronetManifest() {} 42 43 @VisibleForTesting 44 static final String META_DATA_HOLDER_SERVICE_NAME = "android.net.http.MetaDataHolder"; 45 46 @VisibleForTesting 47 static final String ENABLE_TELEMETRY_META_DATA_KEY = "android.net.http.EnableTelemetry"; 48 49 // DO NOT ENABLE this manifest flag in production apps. The code gated behind this flag is not 50 // ready yet. 51 // TODO: remove the "Experimental" prefix once the code for reading HTTP flags is ready. 52 @VisibleForTesting 53 public static final String READ_HTTP_FLAGS_META_DATA_KEY = 54 "android.net.http.EXPERIMENTAL_ReadHttpFlags"; 55 56 /** 57 * @return True if telemetry should be enabled, based on the {@link 58 * #ENABLE_TELEMETRY_META_DATA_KEY} meta-data entry in the Android manifest. 59 */ isAppOptedInForTelemetry(Context context, CronetSource source)60 public static boolean isAppOptedInForTelemetry(Context context, CronetSource source) { 61 boolean telemetryIsDefaultEnabled = 62 source == CronetSource.CRONET_SOURCE_PLATFORM 63 || source == CronetSource.CRONET_SOURCE_PLAY_SERVICES; 64 return getMetaData(context) 65 .getBoolean( 66 ENABLE_TELEMETRY_META_DATA_KEY, /* default= */ telemetryIsDefaultEnabled); 67 } 68 69 /** 70 * @return True if HTTP flags (typically used for experiments) should be enabled, based on the 71 * {@link #READ_HTTP_FLAGS_META_DATA_KEY} meta-data entry in the Android manifest. 72 * @see HttpFlagsLoader 73 */ shouldReadHttpFlags(Context context)74 public static boolean shouldReadHttpFlags(Context context) { 75 // TODO: switch the default to true once we confirm the HTTP flags system is working as 76 // intended. 77 return getMetaData(context).getBoolean(READ_HTTP_FLAGS_META_DATA_KEY, /* default= */ false); 78 } 79 80 /** 81 * @return The meta-data contained within the Cronet meta-data holder service definition in the 82 * Android manifest, or an empty Bundle if there is no such definition. Never returns null. 83 */ getMetaData(Context context)84 private static Bundle getMetaData(Context context) { 85 ServiceInfo serviceInfo; 86 try { 87 serviceInfo = 88 context.getPackageManager() 89 .getServiceInfo( 90 new ComponentName(context, META_DATA_HOLDER_SERVICE_NAME), 91 PackageManager.GET_META_DATA 92 | PackageManager.MATCH_DISABLED_COMPONENTS 93 | PackageManager.MATCH_DIRECT_BOOT_AWARE 94 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); 95 } catch (PackageManager.NameNotFoundException e) { 96 serviceInfo = null; 97 } 98 return serviceInfo != null ? serviceInfo.metaData : new Bundle(); 99 } 100 } 101