Add RlzPingHandler

Adds a class to handle rlz pings with custom brands and stream of
events on Android. Uses the already defined constants for constructing
the request, but has its own URLFetcher logic to make the request.

Depends on https://codereview.chromium.org/2857343004#

BUG=713956

Review-Url: https://codereview.chromium.org/2866633002
Cr-Commit-Position: refs/heads/master@{#470347}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 9092afd..7d2c79d3 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2962,6 +2962,8 @@
       "android/resource_mapper.h",
       "android/rlz/revenue_stats.cc",
       "android/rlz/revenue_stats.h",
+      "android/rlz/rlz_ping_handler.cc",
+      "android/rlz/rlz_ping_handler.h",
       "android/search_geolocation/search_geolocation_disclosure_infobar_delegate.cc",
       "android/search_geolocation/search_geolocation_disclosure_infobar_delegate.h",
       "android/search_geolocation/search_geolocation_disclosure_tab_helper.cc",
@@ -3183,6 +3185,7 @@
       "//components/safe_browsing_db",
       "//components/toolbar",
       "//components/web_contents_delegate_android",
+      "//rlz:rlz_utils",
       "//sandbox:sandbox_features",
       "//third_party/android_opengl/etc1",
       "//third_party/android_tools:cpu_features",
@@ -4221,6 +4224,7 @@
       "../android/java/src/org/chromium/chrome/browser/push_messaging/PushMessagingServiceObserver.java",
       "../android/java/src/org/chromium/chrome/browser/rappor/RapporServiceBridge.java",
       "../android/java/src/org/chromium/chrome/browser/rlz/RevenueStats.java",
+      "../android/java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java",
       "../android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java",
       "../android/java/src/org/chromium/chrome/browser/sessions/SessionTabHelper.java",
       "../android/java/src/org/chromium/chrome/browser/signin/AccountManagementScreenHelper.java",
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index 8d4a2ab1..b7110fd9 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -95,6 +95,7 @@
 #include "chrome/browser/android/rappor/rappor_service_bridge.h"
 #include "chrome/browser/android/recently_closed_tabs_bridge.h"
 #include "chrome/browser/android/rlz/revenue_stats.h"
+#include "chrome/browser/android/rlz/rlz_ping_handler.h"
 #include "chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.h"
 #include "chrome/browser/android/service_tab_launcher.h"
 #include "chrome/browser/android/sessions/session_tab_helper_android.h"
@@ -395,6 +396,7 @@
     {"ResourcePrefetchPredictor",
      predictors::RegisterResourcePrefetchPredictor},
     {"RevenueStats", chrome::android::RegisterRevenueStats},
+    {"RlzPingHandler", chrome::android::RegisterRlzPingHandler},
     {"SafeBrowsing", safe_browsing::android::RegisterBrowserJNI},
     {"SceneLayer", RegisterSceneLayer},
     {"ScreenshotTask", chrome::android::RegisterScreenshotTask},
diff --git a/chrome/browser/android/rlz/rlz_ping_handler.cc b/chrome/browser/android/rlz/rlz_ping_handler.cc
new file mode 100644
index 0000000..53723c44
--- /dev/null
+++ b/chrome/browser/android/rlz/rlz_ping_handler.cc
@@ -0,0 +1,145 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/rlz/rlz_ping_handler.h"
+
+#include "base/android/callback_android.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/profiles/profile_android.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "jni/RlzPingHandler_jni.h"
+#include "net/base/url_util.h"
+#include "net/http/http_status_code.h"
+#include "net/http/http_util.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "rlz/lib/lib_values.h"
+#include "rlz/lib/net_response_check.h"
+#include "url/gurl.h"
+
+using base::android::ConvertJavaStringToUTF16;
+using base::android::JavaParamRef;
+
+constexpr int kMaxRetries = 10;
+
+namespace chrome {
+namespace android {
+
+RlzPingHandler::RlzPingHandler(jobject jprofile) {
+  Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
+  DCHECK(profile);
+  request_context_ = profile->GetRequestContext();
+}
+
+RlzPingHandler::~RlzPingHandler() = default;
+
+void RlzPingHandler::Ping(
+    const base::android::JavaParamRef<jstring>& j_brand,
+    const base::android::JavaParamRef<jstring>& j_language,
+    const base::android::JavaParamRef<jstring>& j_events,
+    const base::android::JavaParamRef<jstring>& j_id,
+    const base::android::JavaParamRef<jobject>& j_callback) {
+  if (!j_brand || !j_language || !j_events || !j_id || !j_callback) {
+    base::android::RunCallbackAndroid(j_callback, false);
+    delete this;
+    return;
+  }
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  j_callback_.Reset(env, j_callback);
+  std::string brand = ConvertJavaStringToUTF8(env, j_brand);
+  std::string language = ConvertJavaStringToUTF8(env, j_language);
+  std::string events = ConvertJavaStringToUTF8(env, j_events);
+  std::string id = ConvertJavaStringToUTF8(env, j_id);
+
+  DCHECK_EQ(brand.length(), 4u);
+  DCHECK_EQ(language.length(), 2u);
+  DCHECK_EQ(id.length(), 50u);
+
+  GURL request_url(base::StringPrintf(
+      "https://%s%s?", rlz_lib::kFinancialServer, rlz_lib::kFinancialPingPath));
+  request_url = net::AppendQueryParameter(
+      request_url, rlz_lib::kProductSignatureCgiVariable, "chrome");
+  request_url = net::AppendQueryParameter(
+      request_url, rlz_lib::kProductBrandCgiVariable, brand);
+  request_url = net::AppendQueryParameter(
+      request_url, rlz_lib::kProductLanguageCgiVariable, language);
+  request_url = net::AppendQueryParameter(request_url,
+                                          rlz_lib::kEventsCgiVariable, events);
+  request_url = net::AppendQueryParameter(request_url,
+                                          rlz_lib::kMachineIdCgiVariable, id);
+
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("rlz", R"(
+          semantics {
+            sender: "RLZ Ping Handler"
+            description:
+            "Sends rlz pings for revenue related tracking to the designated web"
+            "end point."
+            trigger:
+            "Critical signals like first install, a promotion dialog being"
+            "shown, a user selection for a promotion may trigger a ping"
+            destination: WEBSITE
+          }
+          policy {
+            cookies_allowed: true
+            cookies_store: "user"
+            setting: "Not user controlled. But it uses a trusted web end point"
+                     "that doesn't use user data"
+            policy_exception_justification:
+              "Not implemented, considered not useful as no content is being "
+              "uploaded."
+          })");
+
+  url_fetcher_ = net::URLFetcher::Create(0, request_url, net::URLFetcher::GET,
+                                         this, traffic_annotation);
+  url_fetcher_->SetMaxRetriesOn5xx(kMaxRetries);
+  url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
+  url_fetcher_->SetAutomaticallyRetryOn5xx(true);
+  url_fetcher_->SetRequestContext(request_context_.get());
+  url_fetcher_->Start();
+}
+
+void RlzPingHandler::OnURLFetchComplete(const net::URLFetcher* source) {
+  DCHECK_EQ(source, url_fetcher_.get());
+
+  jboolean valid = false;
+  if (!source->GetStatus().is_success() ||
+      source->GetResponseCode() != net::HTTP_OK) {
+    LOG(WARNING) << base::StringPrintf("Rlz endpoint responded with code %d.",
+                                       source->GetResponseCode());
+  } else {
+    std::string response;
+    source->GetResponseAsString(&response);
+    int response_length = -1;
+    valid = rlz_lib::IsPingResponseValid(response.c_str(), &response_length);
+  }
+
+  // TODO(yusufo) : Investigate what else can be checked for validity that is
+  // specific to the ping
+  base::android::RunCallbackAndroid(j_callback_, valid);
+  delete this;
+}
+
+void StartPing(JNIEnv* env,
+               const JavaParamRef<jclass>& clazz,
+               const base::android::JavaParamRef<jobject>& j_profile,
+               const base::android::JavaParamRef<jstring>& j_brand,
+               const base::android::JavaParamRef<jstring>& j_language,
+               const base::android::JavaParamRef<jstring>& j_events,
+               const base::android::JavaParamRef<jstring>& j_id,
+               const base::android::JavaParamRef<jobject>& j_callback) {
+  RlzPingHandler* handler = new RlzPingHandler(j_profile);
+  handler->Ping(j_brand, j_language, j_events, j_id, j_callback);
+}
+
+// Register native methods
+bool RegisterRlzPingHandler(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace chrome
diff --git a/chrome/browser/android/rlz/rlz_ping_handler.h b/chrome/browser/android/rlz/rlz_ping_handler.h
new file mode 100644
index 0000000..2abe720
--- /dev/null
+++ b/chrome/browser/android/rlz/rlz_ping_handler.h
@@ -0,0 +1,51 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_RLZ_RLZ_PING_HANDLER_H_
+#define CHROME_BROWSER_ANDROID_RLZ_RLZ_PING_HANDLER_H_
+
+#include <jni.h>
+#include "base/android/scoped_java_ref.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace chrome {
+namespace android {
+
+// JNI bridge for   RlzPingHandler.java
+class RlzPingHandler : public net::URLFetcherDelegate {
+ public:
+  explicit RlzPingHandler(jobject jprofile);
+  ~RlzPingHandler() override;
+
+  // Makes a GET request to the designated web end point with the given
+  // parameters. |j_brand| is a 4 character priorly designated brand value.
+  // |j_language| is the 2 letter lower case language. |events| is a single
+  // string where multiple 4 character long events are concatenated with ,
+  // and |id| is a unique id for the device that is 50 characters long.
+  void Ping(const base::android::JavaParamRef<jstring>& j_brand,
+            const base::android::JavaParamRef<jstring>& j_language,
+            const base::android::JavaParamRef<jstring>& j_events,
+            const base::android::JavaParamRef<jstring>& j_id,
+            const base::android::JavaParamRef<jobject>& j_callback);
+
+ private:
+  // net::URLFetcherDelegate:
+  void OnURLFetchComplete(const net::URLFetcher* source) override;
+
+  scoped_refptr<net::URLRequestContextGetter> request_context_;
+
+  std::unique_ptr<net::URLFetcher> url_fetcher_;
+  base::android::ScopedJavaGlobalRef<jobject> j_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(RlzPingHandler);
+};
+
+bool RegisterRlzPingHandler(JNIEnv* env);
+
+}  // namespace android
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_ANDROID_RLZ_RLZ_PING_HANDLER_H_