1 // Copyright 2014 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 #include <jni.h>
6
7 #include <map>
8 #include <string>
9
10 #include "base/base_jni/FieldTrialList_jni.h"
11 #include "base/lazy_instance.h"
12 #include "base/metrics/field_trial.h"
13 #include "base/metrics/field_trial_list_including_low_anonymity.h"
14 #include "base/metrics/field_trial_params.h"
15
16 namespace {
17
18 // Log trials and their groups on activation, for debugging purposes.
19 class TrialLogger : public base::FieldTrialList::Observer {
20 public:
TrialLogger()21 TrialLogger() {}
22
23 TrialLogger(const TrialLogger&) = delete;
24 TrialLogger& operator=(const TrialLogger&) = delete;
25
OnFieldTrialGroupFinalized(const base::FieldTrial & trial,const std::string & group_name)26 void OnFieldTrialGroupFinalized(const base::FieldTrial& trial,
27 const std::string& group_name) override {
28 Log(trial.trial_name(), group_name);
29 }
30
Log(const std::string & trial_name,const std::string & group_name)31 static void Log(const std::string& trial_name,
32 const std::string& group_name) {
33 // Changes to format of the log message below must be accompanied by
34 // changes to finch smoke tests since they look for this log message
35 // in the logcat.
36 LOG(INFO) << "Active field trial \"" << trial_name
37 << "\" in group \"" << group_name<< '"';
38 }
39
40 protected:
~TrialLogger()41 ~TrialLogger() override {}
42 };
43
44 base::LazyInstance<TrialLogger>::Leaky g_trial_logger =
45 LAZY_INSTANCE_INITIALIZER;
46
47 } // namespace
48
JNI_FieldTrialList_FindFullName(JNIEnv * env,std::string & trial_name)49 static std::string JNI_FieldTrialList_FindFullName(JNIEnv* env,
50 std::string& trial_name) {
51 return base::FieldTrialList::FindFullName(trial_name);
52 }
53
JNI_FieldTrialList_TrialExists(JNIEnv * env,std::string & trial_name)54 static jboolean JNI_FieldTrialList_TrialExists(JNIEnv* env,
55 std::string& trial_name) {
56 return base::FieldTrialList::TrialExists(trial_name);
57 }
58
JNI_FieldTrialList_GetVariationParameter(JNIEnv * env,std::string & trial_name,std::string & parameter_key)59 static std::string JNI_FieldTrialList_GetVariationParameter(
60 JNIEnv* env,
61 std::string& trial_name,
62 std::string& parameter_key) {
63 std::map<std::string, std::string> parameters;
64 base::GetFieldTrialParams(trial_name, ¶meters);
65 return parameters[parameter_key];
66 }
67
68 // JNI_FieldTrialList_LogActiveTrials() is static function, this makes friending
69 // it a hassle because it must be declared in the file that the friend
70 // declaration is in, but its declaration can't be included in multiple places
71 // or things get messy and the linker gets mad. This helper class exists only to
72 // friend the JNI function and is, in turn, friended by
73 // FieldTrialListIncludingLowAnonymity which allows for the private
74 // GetActiveFieldTrialGroups() to be reached.
75 class AndroidFieldTrialListLogActiveTrialsFriendHelper {
76 private:
77 friend void ::JNI_FieldTrialList_LogActiveTrials(JNIEnv* env);
78
AddObserver(base::FieldTrialList::Observer * observer)79 static bool AddObserver(base::FieldTrialList::Observer* observer) {
80 return base::FieldTrialListIncludingLowAnonymity::AddObserver(observer);
81 }
82
GetActiveFieldTrialGroups(base::FieldTrial::ActiveGroups * active_groups)83 static void GetActiveFieldTrialGroups(
84 base::FieldTrial::ActiveGroups* active_groups) {
85 base::FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups(
86 active_groups);
87 }
88 };
89
JNI_FieldTrialList_LogActiveTrials(JNIEnv * env)90 static void JNI_FieldTrialList_LogActiveTrials(JNIEnv* env) {
91 DCHECK(!g_trial_logger.IsCreated()); // This need only be called once.
92
93 LOG(INFO) << "Logging active field trials...";
94 AndroidFieldTrialListLogActiveTrialsFriendHelper::AddObserver(
95 &g_trial_logger.Get());
96
97 // Log any trials that were already active before adding the observer.
98 std::vector<base::FieldTrial::ActiveGroup> active_groups;
99 AndroidFieldTrialListLogActiveTrialsFriendHelper::GetActiveFieldTrialGroups(
100 &active_groups);
101 for (const base::FieldTrial::ActiveGroup& group : active_groups) {
102 TrialLogger::Log(group.trial_name, group.group_name);
103 }
104 }
105
JNI_FieldTrialList_CreateFieldTrial(JNIEnv * env,std::string & trial_name,std::string & group_name)106 static jboolean JNI_FieldTrialList_CreateFieldTrial(JNIEnv* env,
107 std::string& trial_name,
108 std::string& group_name) {
109 return base::FieldTrialList::CreateFieldTrial(trial_name, group_name) !=
110 nullptr;
111 }
112