• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Context;
8 import android.os.Build;
9 import android.util.Log; // TODO(crbug/1394709): use org.chromium.base.Log instead
10 
11 import androidx.annotation.Nullable;
12 import androidx.annotation.VisibleForTesting;
13 
14 import org.chromium.net.impl.CronetLogger.CronetSource;
15 
16 /**
17  * Takes care of instantiating the correct CronetLogger.
18  */
19 public final class CronetLoggerFactory {
20     private static final String TAG = CronetLoggerFactory.class.getSimpleName();
21     private static final int SAMPLE_RATE_PER_SECOND = 1;
22 
CronetLoggerFactory()23     private CronetLoggerFactory() {}
24 
25     private static final CronetLogger sDefaultLogger = new NoOpLogger();
26     private static CronetLogger sTestingLogger;
27 
28     // Class that is packaged for Cronet telemetry.
29     private static final String CRONET_LOGGER_IMPL_CLASS =
30             "com.google.net.cronet.telemetry.CronetLoggerImpl";
31 
32     /**
33      * Bypasses CronetLoggerFactory logic and always creates a NoOpLogger.
34      * To be used only as a kill-switch for logging.
35      * @return a NoOpLogger instance.
36      */
createNoOpLogger()37     public static CronetLogger createNoOpLogger() {
38         return sDefaultLogger;
39     }
40 
41     /**
42      * @return The correct CronetLogger to be used for logging.
43      */
createLogger(Context ctx, CronetSource source)44     public static CronetLogger createLogger(Context ctx, CronetSource source) {
45         if (sTestingLogger != null) return sTestingLogger;
46 
47         // The CronetLoggerImpl only works from apiLevel 30
48         if (!CronetManifest.isAppOptedInForTelemetry(ctx, source)
49                 || Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
50             return sDefaultLogger;
51         }
52 
53         Class<? extends CronetLogger> cronetLoggerImplClass = fetchLoggerImplClass();
54         if (cronetLoggerImplClass == null) return sDefaultLogger;
55 
56         try {
57             return cronetLoggerImplClass.getConstructor(int.class).newInstance(
58                     SAMPLE_RATE_PER_SECOND);
59         } catch (Exception e) {
60             // Pass - since we dont want any failure, catch any exception that might arise.
61             Log.e(TAG, "Exception creating an instance of CronetLoggerImpl", e);
62         }
63         return sDefaultLogger;
64     }
65 
66     @VisibleForTesting
setLoggerForTesting(@ullable CronetLogger testingLogger)67     public static void setLoggerForTesting(@Nullable CronetLogger testingLogger) {
68         sTestingLogger = testingLogger;
69     }
70 
fetchLoggerImplClass()71     private static Class<? extends CronetLogger> fetchLoggerImplClass() {
72         ClassLoader loader = CronetLoggerFactory.class.getClassLoader();
73         try {
74             return loader.loadClass(CRONET_LOGGER_IMPL_CLASS).asSubclass(CronetLogger.class);
75         } catch (Exception e) { // catching all exceptions since we don't want to crash the client
76             Log.e(TAG, "Exception fetching LoggerImpl class", e);
77             return null;
78         }
79     }
80 }
81