aw_metrics_service_client.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "android_webview/browser/metrics/aw_metrics_service_client.h"
  5. #include <jni.h>
  6. #include <cstdint>
  7. #include "android_webview/browser_jni_headers/AwMetricsServiceClient_jni.h"
  8. #include "android_webview/common/aw_features.h"
  9. #include "android_webview/common/metrics/app_package_name_logging_rule.h"
  10. #include "base/android/callback_android.h"
  11. #include "base/android/jni_android.h"
  12. #include "base/android/jni_string.h"
  13. #include "base/base_paths_android.h"
  14. #include "base/feature_list.h"
  15. #include "base/files/file_util.h"
  16. #include "base/metrics/histogram_functions.h"
  17. #include "base/metrics/persistent_histogram_allocator.h"
  18. #include "base/path_service.h"
  19. #include "base/task/task_traits.h"
  20. #include "base/task/thread_pool.h"
  21. #include "base/time/time.h"
  22. #include "base/trace_event/trace_event.h"
  23. #include "components/metrics/metrics_pref_names.h"
  24. #include "components/metrics/metrics_service.h"
  25. #include "components/prefs/pref_service.h"
  26. #include "components/version_info/android/channel_getter.h"
  27. namespace android_webview {
  28. namespace prefs {
  29. const char kMetricsAppPackageNameLoggingRule[] =
  30. "aw_metrics_app_package_name_logging_rule";
  31. const char kAppPackageNameLoggingRuleLastUpdateTime[] =
  32. "aw_metrics_app_package_name_logging_rule_last_update";
  33. } // namespace prefs
  34. namespace {
  35. // IMPORTANT: DO NOT CHANGE sample rates without first ensuring the Chrome
  36. // Metrics team has the appropriate backend bandwidth and storage.
  37. // Sample at 2%, based on storage concerns. We sample at a different rate than
  38. // Chrome because we have more metrics "clients" (each app on the device counts
  39. // as a separate client).
  40. const int kStableSampledInRatePerMille = 20;
  41. // Sample non-stable channels at 99%, to boost volume for pre-stable
  42. // experiments. We choose 99% instead of 100% for consistency with Chrome and to
  43. // exercise the out-of-sample code path.
  44. const int kBetaDevCanarySampledInRatePerMille = 990;
  45. // The fraction of UMA clients for whom package name data is uploaded. This
  46. // threshold and the corresponding privacy requirements are described in more
  47. // detail at http://shortn/_CzfDUxTxm2 (internal document). We also have public
  48. // documentation for metrics collection in WebView more generally (see
  49. // https://developer.android.com/guide/webapps/webview-privacy).
  50. //
  51. // Do not change this constant without seeking privacy approval with the teams
  52. // outlined in the internal document above.
  53. const int kPackageNameLimitRatePerMille = 100; // (10% of UMA clients)
  54. AwMetricsServiceClient* g_aw_metrics_service_client = nullptr;
  55. } // namespace
  56. const base::TimeDelta kRecordAppDataDirectorySizeDelay = base::Seconds(10);
  57. AwMetricsServiceClient::Delegate::Delegate() = default;
  58. AwMetricsServiceClient::Delegate::~Delegate() = default;
  59. // static
  60. AwMetricsServiceClient* AwMetricsServiceClient::GetInstance() {
  61. DCHECK(g_aw_metrics_service_client);
  62. g_aw_metrics_service_client->EnsureOnValidSequence();
  63. return g_aw_metrics_service_client;
  64. }
  65. // static
  66. void AwMetricsServiceClient::SetInstance(
  67. std::unique_ptr<AwMetricsServiceClient> aw_metrics_service_client) {
  68. DCHECK(!g_aw_metrics_service_client);
  69. DCHECK(aw_metrics_service_client);
  70. g_aw_metrics_service_client = aw_metrics_service_client.release();
  71. g_aw_metrics_service_client->EnsureOnValidSequence();
  72. }
  73. AwMetricsServiceClient::AwMetricsServiceClient(
  74. std::unique_ptr<Delegate> delegate)
  75. : time_created_(base::Time::Now()), delegate_(std::move(delegate)) {}
  76. AwMetricsServiceClient::~AwMetricsServiceClient() = default;
  77. int32_t AwMetricsServiceClient::GetProduct() {
  78. return metrics::ChromeUserMetricsExtension::ANDROID_WEBVIEW;
  79. }
  80. int AwMetricsServiceClient::GetSampleRatePerMille() const {
  81. // Down-sample unknown channel as a precaution in case it ends up being
  82. // shipped to Stable users.
  83. version_info::Channel channel = version_info::android::GetChannel();
  84. if (channel == version_info::Channel::STABLE ||
  85. channel == version_info::Channel::UNKNOWN) {
  86. return kStableSampledInRatePerMille;
  87. }
  88. return kBetaDevCanarySampledInRatePerMille;
  89. }
  90. std::string AwMetricsServiceClient::GetAppPackageNameIfLoggable() {
  91. AndroidMetricsServiceClient::InstallerPackageType installer_type =
  92. GetInstallerPackageType();
  93. // Always record the app package name of system apps even if it's not in the
  94. // allowlist.
  95. if (installer_type == InstallerPackageType::SYSTEM_APP ||
  96. (installer_type == InstallerPackageType::GOOGLE_PLAY_STORE &&
  97. ShouldRecordPackageName())) {
  98. return GetAppPackageName();
  99. }
  100. return std::string();
  101. }
  102. bool AwMetricsServiceClient::ShouldRecordPackageName() {
  103. base::UmaHistogramEnumeration(
  104. "Android.WebView.Metrics.PackagesAllowList.RecordStatus",
  105. package_name_record_status_);
  106. return cached_package_name_record_.has_value() &&
  107. cached_package_name_record_.value().IsAppPackageNameAllowed();
  108. }
  109. void AwMetricsServiceClient::SetAppPackageNameLoggingRule(
  110. absl::optional<AppPackageNameLoggingRule> record) {
  111. absl::optional<AppPackageNameLoggingRule> cached_record =
  112. GetCachedAppPackageNameLoggingRule();
  113. if (!record.has_value()) {
  114. package_name_record_status_ =
  115. cached_record.has_value()
  116. ? AppPackageNameLoggingRuleStatus::kNewVersionFailedUseCache
  117. : AppPackageNameLoggingRuleStatus::kNewVersionFailedNoCache;
  118. return;
  119. }
  120. if (cached_record.has_value() &&
  121. record.value().IsSameAs(cached_package_name_record_.value())) {
  122. package_name_record_status_ =
  123. AppPackageNameLoggingRuleStatus::kSameVersionAsCache;
  124. return;
  125. }
  126. PrefService* local_state = pref_service();
  127. DCHECK(local_state);
  128. local_state->Set(prefs::kMetricsAppPackageNameLoggingRule,
  129. record.value().ToDictionary());
  130. cached_package_name_record_ = record;
  131. package_name_record_status_ =
  132. AppPackageNameLoggingRuleStatus::kNewVersionLoaded;
  133. UmaHistogramTimes(
  134. "Android.WebView.Metrics.PackagesAllowList.ResultReceivingDelay",
  135. base::Time::Now() - time_created_);
  136. }
  137. absl::optional<AppPackageNameLoggingRule>
  138. AwMetricsServiceClient::GetCachedAppPackageNameLoggingRule() {
  139. if (cached_package_name_record_.has_value()) {
  140. return cached_package_name_record_;
  141. }
  142. PrefService* local_state = pref_service();
  143. DCHECK(local_state);
  144. cached_package_name_record_ = AppPackageNameLoggingRule::FromDictionary(
  145. local_state->GetValue(prefs::kMetricsAppPackageNameLoggingRule));
  146. if (cached_package_name_record_.has_value()) {
  147. package_name_record_status_ =
  148. AppPackageNameLoggingRuleStatus::kNotLoadedUseCache;
  149. }
  150. return cached_package_name_record_;
  151. }
  152. base::Time AwMetricsServiceClient::GetAppPackageNameLoggingRuleLastUpdateTime()
  153. const {
  154. PrefService* local_state = pref_service();
  155. DCHECK(local_state);
  156. return local_state->GetTime(prefs::kAppPackageNameLoggingRuleLastUpdateTime);
  157. }
  158. void AwMetricsServiceClient::SetAppPackageNameLoggingRuleLastUpdateTime(
  159. base::Time update_time) {
  160. PrefService* local_state = pref_service();
  161. DCHECK(local_state);
  162. local_state->SetTime(prefs::kAppPackageNameLoggingRuleLastUpdateTime,
  163. update_time);
  164. }
  165. // Used below in AwMetricsServiceClient::OnMetricsStart.
  166. void RecordAppDataDirectorySize() {
  167. TRACE_EVENT_BEGIN0("android_webview", "RecordAppDataDirectorySize");
  168. base::TimeTicks start_time = base::TimeTicks::Now();
  169. base::FilePath app_data_dir;
  170. base::PathService::Get(base::DIR_ANDROID_APP_DATA, &app_data_dir);
  171. int64_t bytes = base::ComputeDirectorySize(app_data_dir);
  172. // Record size up to 100MB
  173. base::UmaHistogramCounts100000("Android.WebView.AppDataDirectory.Size",
  174. bytes / 1024);
  175. base::UmaHistogramMediumTimes(
  176. "Android.WebView.AppDataDirectory.TimeToComputeSize",
  177. base::TimeTicks::Now() - start_time);
  178. TRACE_EVENT_END0("android_webview", "RecordAppDataDirectorySize");
  179. }
  180. void AwMetricsServiceClient::OnMetricsStart() {
  181. delegate_->AddWebViewAppStateObserver(this);
  182. if (base::FeatureList::IsEnabled(
  183. android_webview::features::kWebViewRecordAppDataDirectorySize) &&
  184. IsReportingEnabled()) {
  185. // Calculating directory size can be fairly expensive, so only do this when
  186. // we are certain that the UMA histogram will be logged to the server.
  187. base::ThreadPool::PostDelayedTask(
  188. FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
  189. base::BindOnce(&RecordAppDataDirectorySize),
  190. kRecordAppDataDirectorySizeDelay);
  191. }
  192. }
  193. void AwMetricsServiceClient::OnMetricsNotStarted() {}
  194. int AwMetricsServiceClient::GetPackageNameLimitRatePerMille() {
  195. return kPackageNameLimitRatePerMille;
  196. }
  197. void AwMetricsServiceClient::OnAppStateChanged(
  198. WebViewAppStateObserver::State state) {
  199. // To match MetricsService's expectation,
  200. // - does nothing if no WebView has ever been created.
  201. // - starts notifying MetricsService once a WebView is created and the app
  202. // is foreground.
  203. // - consolidates the other states other than kForeground into background.
  204. // - avoids the duplicated notification.
  205. if (state == WebViewAppStateObserver::State::kDestroyed &&
  206. !delegate_->HasAwContentsEverCreated()) {
  207. return;
  208. }
  209. bool foreground = state == WebViewAppStateObserver::State::kForeground;
  210. if (foreground == app_in_foreground_)
  211. return;
  212. app_in_foreground_ = foreground;
  213. if (app_in_foreground_) {
  214. GetMetricsService()->OnAppEnterForeground();
  215. } else {
  216. // TODO(https://crbug.com/1052392): Turn on the background recording.
  217. // Not recording in background, this matches Chrome's behavior.
  218. GetMetricsService()->OnAppEnterBackground(
  219. /* keep_recording_in_background = false */);
  220. }
  221. }
  222. void AwMetricsServiceClient::RegisterAdditionalMetricsProviders(
  223. metrics::MetricsService* service) {
  224. delegate_->RegisterAdditionalMetricsProviders(service);
  225. }
  226. // static
  227. void AwMetricsServiceClient::RegisterMetricsPrefs(
  228. PrefRegistrySimple* registry) {
  229. RegisterPrefs(registry);
  230. registry->RegisterDictionaryPref(prefs::kMetricsAppPackageNameLoggingRule,
  231. base::Value(base::Value::Type::DICTIONARY));
  232. registry->RegisterTimePref(prefs::kAppPackageNameLoggingRuleLastUpdateTime,
  233. base::Time());
  234. }
  235. // static
  236. void JNI_AwMetricsServiceClient_SetHaveMetricsConsent(JNIEnv* env,
  237. jboolean user_consent,
  238. jboolean app_consent) {
  239. AwMetricsServiceClient::GetInstance()->SetHaveMetricsConsent(user_consent,
  240. app_consent);
  241. }
  242. // static
  243. void JNI_AwMetricsServiceClient_SetFastStartupForTesting(
  244. JNIEnv* env,
  245. jboolean fast_startup_for_testing) {
  246. AwMetricsServiceClient::GetInstance()->SetFastStartupForTesting(
  247. fast_startup_for_testing);
  248. }
  249. // static
  250. void JNI_AwMetricsServiceClient_SetUploadIntervalForTesting(
  251. JNIEnv* env,
  252. jlong upload_interval_ms) {
  253. AwMetricsServiceClient::GetInstance()->SetUploadIntervalForTesting(
  254. base::Milliseconds(upload_interval_ms));
  255. }
  256. // static
  257. void JNI_AwMetricsServiceClient_SetOnFinalMetricsCollectedListenerForTesting(
  258. JNIEnv* env,
  259. const base::android::JavaParamRef<jobject>& listener) {
  260. AwMetricsServiceClient::GetInstance()
  261. ->SetOnFinalMetricsCollectedListenerForTesting(base::BindRepeating(
  262. base::android::RunRunnableAndroid,
  263. base::android::ScopedJavaGlobalRef<jobject>(listener)));
  264. }
  265. // static
  266. void JNI_AwMetricsServiceClient_SetAppPackageNameLoggingRuleForTesting(
  267. JNIEnv* env,
  268. const base::android::JavaParamRef<jstring>& version,
  269. jlong expiry_date_ms) {
  270. AwMetricsServiceClient::GetInstance()->SetAppPackageNameLoggingRule(
  271. AppPackageNameLoggingRule(
  272. base::Version(base::android::ConvertJavaStringToUTF8(env, version)),
  273. base::Time::UnixEpoch() + base::Milliseconds(expiry_date_ms)));
  274. }
  275. } // namespace android_webview