// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/feed/android/feed_reliability_logging_bridge.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/time/time.h"
#include "components/feed/core/v2/public/types.h"
#include "net/base/net_errors.h"
#include "net/http/http_status_code.h"
#include "third_party/abseil-cpp/absl/status/status.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/browser/feed/android/jni_headers/FeedReliabilityLoggingBridge_jni.h"
using base::android::ScopedJavaLocalRef;
namespace feed {
namespace android {
namespace {
jlong ConvertTimestamp(base::TimeTicks ticks) {
return ticks.since_origin().InNanoseconds();
}
// Note: we're using `absl::StatusCode` for logging network request status
// because it is kept in sync with the proto enum `google.rpc.Code`, which is
// the format the server expects and which is less convenient to use here than
// `absl::StatusCode`.
// https://source.chromium.org/chromium/chromium/src/+/main:third_party/abseil-cpp/absl/status/status.h;drc=083488f5118f2ecf1e927925d9b679f21f8541d0;l=83
// https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto#L32
absl::StatusCode NetErrorToCanonicalStatus(net::Error net_error) {
switch (net_error) {
case net::ERR_NAME_NOT_RESOLVED:
case net::ERR_INTERNET_DISCONNECTED:
case net::ERR_CONNECTION_REFUSED:
case net::ERR_ADDRESS_UNREACHABLE:
case net::ERR_CONNECTION_CLOSED:
return absl::StatusCode::kUnavailable;
case net::ERR_NETWORK_CHANGED:
case net::ERR_CONNECTION_RESET:
return absl::StatusCode::kAborted;
case net::ERR_TIMED_OUT:
case net::ERR_CONNECTION_TIMED_OUT:
return absl::StatusCode::kDeadlineExceeded;
case net::ERR_QUIC_PROTOCOL_ERROR:
default:
return absl::StatusCode::kInternal;
}
}
absl::StatusCode HttpStatusToCanonicalStatus(int http_status) {
switch (http_status) {
case net::HTTP_OK:
return absl::StatusCode::kOk;
case net::HTTP_BAD_REQUEST:
return absl::StatusCode::kInvalidArgument;
case net::HTTP_FORBIDDEN:
return absl::StatusCode::kPermissionDenied;
case net::HTTP_NOT_FOUND:
return absl::StatusCode::kNotFound;
case net::HTTP_CONFLICT:
return absl::StatusCode::kAlreadyExists;
case net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE:
return absl::StatusCode::kOutOfRange;
case net::HTTP_TOO_MANY_REQUESTS:
return absl::StatusCode::kResourceExhausted;
case 499: // Client closed request.
return absl::StatusCode::kCancelled;
case net::HTTP_NOT_IMPLEMENTED:
return absl::StatusCode::kUnimplemented;
case net::HTTP_SERVICE_UNAVAILABLE:
return absl::StatusCode::kUnavailable;
case net::HTTP_GATEWAY_TIMEOUT:
return absl::StatusCode::kDeadlineExceeded;
case net::HTTP_UNAUTHORIZED:
return absl::StatusCode::kUnauthenticated;
}
if (http_status >= 200 && http_status < 300) {
return absl::StatusCode::kOk;
} else if (http_status >= 400 && http_status < 500) {
return absl::StatusCode::kFailedPrecondition;
} else if (http_status >= 500 && http_status < 600) {
return absl::StatusCode::kInternal;
}
return absl::StatusCode::kUnknown;
}
int CombinedNetworkStatusCodeToCanonicalStatus(
int combined_network_status_code) {
absl::StatusCode canonical_code;
if (combined_network_status_code >= 0) {
canonical_code = HttpStatusToCanonicalStatus(combined_network_status_code);
} else {
canonical_code = NetErrorToCanonicalStatus(
static_cast<net::Error>(combined_network_status_code));
}
return static_cast<int>(canonical_code);
}
} // namespace
static jlong JNI_FeedReliabilityLoggingBridge_Init(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_this) {
return reinterpret_cast<intptr_t>(new FeedReliabilityLoggingBridge(j_this));
}
FeedReliabilityLoggingBridge::FeedReliabilityLoggingBridge(
const base::android::JavaRef<jobject>& j_this)
: java_ref_(j_this) {}
FeedReliabilityLoggingBridge::~FeedReliabilityLoggingBridge() = default;
void FeedReliabilityLoggingBridge::LogFeedLaunchOtherStart(
base::TimeTicks timestamp) {
Java_FeedReliabilityLoggingBridge_logOtherLaunchStart(
base::android::AttachCurrentThread(), java_ref_,
ConvertTimestamp(timestamp));
}
void FeedReliabilityLoggingBridge::LogCacheReadStart(
base::TimeTicks timestamp) {
Java_FeedReliabilityLoggingBridge_logCacheReadStart(
base::android::AttachCurrentThread(), java_ref_,
ConvertTimestamp(timestamp));
}
void FeedReliabilityLoggingBridge::LogCacheReadEnd(
base::TimeTicks timestamp,
feedwire::DiscoverCardReadCacheResult result) {
Java_FeedReliabilityLoggingBridge_logCacheReadEnd(
base::android::AttachCurrentThread(), java_ref_,
ConvertTimestamp(timestamp), result);
}
void FeedReliabilityLoggingBridge::LogFeedRequestStart(
NetworkRequestId id,
base::TimeTicks timestamp) {
Java_FeedReliabilityLoggingBridge_logFeedRequestStart(
base::android::AttachCurrentThread(), java_ref_, id.GetUnsafeValue(),
ConvertTimestamp(timestamp));
}
void FeedReliabilityLoggingBridge::LogActionsUploadRequestStart(
NetworkRequestId id,
base::TimeTicks timestamp) {
Java_FeedReliabilityLoggingBridge_logActionsUploadRequestStart(
base::android::AttachCurrentThread(), java_ref_, id.GetUnsafeValue(),
ConvertTimestamp(timestamp));
}
void FeedReliabilityLoggingBridge::LogWebFeedRequestStart(
NetworkRequestId id,
base::TimeTicks timestamp) {
Java_FeedReliabilityLoggingBridge_logWebFeedRequestStart(
base::android::AttachCurrentThread(), java_ref_, id.GetUnsafeValue(),
ConvertTimestamp(timestamp));
}
void FeedReliabilityLoggingBridge::LogSingleWebFeedRequestStart(
NetworkRequestId id,
base::TimeTicks timestamp) {
Java_FeedReliabilityLoggingBridge_logSingleWebFeedRequestStart(
base::android::AttachCurrentThread(), java_ref_, id.GetUnsafeValue(),
ConvertTimestamp(timestamp));
}
void FeedReliabilityLoggingBridge::LogRequestSent(NetworkRequestId id,
base::TimeTicks timestamp) {
Java_FeedReliabilityLoggingBridge_logRequestSent(
base::android::AttachCurrentThread(), java_ref_, id.GetUnsafeValue(),
ConvertTimestamp(timestamp));
}
void FeedReliabilityLoggingBridge::LogResponseReceived(
NetworkRequestId id,
int64_t server_receive_timestamp_ns,
int64_t server_send_timestamp_ns,
base::TimeTicks client_receive_timestamp) {
Java_FeedReliabilityLoggingBridge_logResponseReceived(
base::android::AttachCurrentThread(), java_ref_, id.GetUnsafeValue(),
server_receive_timestamp_ns, server_send_timestamp_ns,
ConvertTimestamp(client_receive_timestamp));
}
void FeedReliabilityLoggingBridge::LogRequestFinished(
NetworkRequestId id,
base::TimeTicks timestamp,
int combined_network_status_code) {
Java_FeedReliabilityLoggingBridge_logRequestFinished(
base::android::AttachCurrentThread(), java_ref_, id.GetUnsafeValue(),
ConvertTimestamp(timestamp),
CombinedNetworkStatusCodeToCanonicalStatus(combined_network_status_code));
}
void FeedReliabilityLoggingBridge::LogLoadingIndicatorShown(
base::TimeTicks timestamp) {
Java_FeedReliabilityLoggingBridge_logLoadingIndicatorShown(
base::android::AttachCurrentThread(), java_ref_,
ConvertTimestamp(timestamp));
}
void FeedReliabilityLoggingBridge::LogAboveTheFoldRender(
base::TimeTicks timestamp,
feedwire::DiscoverAboveTheFoldRenderResult result) {
Java_FeedReliabilityLoggingBridge_logAboveTheFoldRender(
base::android::AttachCurrentThread(), java_ref_,
ConvertTimestamp(timestamp), result);
}
void FeedReliabilityLoggingBridge::LogLaunchFinishedAfterStreamUpdate(
feedwire::DiscoverLaunchResult result) {
Java_FeedReliabilityLoggingBridge_logLaunchFinishedAfterStreamUpdate(
base::android::AttachCurrentThread(), java_ref_, result);
}
void FeedReliabilityLoggingBridge::LogLoadMoreStarted() {
Java_FeedReliabilityLoggingBridge_logLoadMoreStarted(
base::android::AttachCurrentThread(), java_ref_);
}
void FeedReliabilityLoggingBridge::LogLoadMoreActionUploadRequestStarted() {
Java_FeedReliabilityLoggingBridge_logLoadMoreActionUploadRequestStarted(
base::android::AttachCurrentThread(), java_ref_);
}
void FeedReliabilityLoggingBridge::LogLoadMoreRequestSent() {
Java_FeedReliabilityLoggingBridge_logLoadMoreRequestSent(
base::android::AttachCurrentThread(), java_ref_);
}
void FeedReliabilityLoggingBridge::LogLoadMoreResponseReceived(
int64_t server_receive_timestamp_ns,
int64_t server_send_timestamp_ns) {
Java_FeedReliabilityLoggingBridge_logLoadMoreResponseReceived(
base::android::AttachCurrentThread(), java_ref_,
server_receive_timestamp_ns, server_send_timestamp_ns);
}
void FeedReliabilityLoggingBridge::LogLoadMoreRequestFinished(
int combined_network_status_code) {
Java_FeedReliabilityLoggingBridge_logLoadMoreRequestFinished(
base::android::AttachCurrentThread(), java_ref_,
CombinedNetworkStatusCodeToCanonicalStatus(combined_network_status_code));
}
void FeedReliabilityLoggingBridge::LogLoadMoreEnded(bool success) {
Java_FeedReliabilityLoggingBridge_logLoadMoreEnded(
base::android::AttachCurrentThread(), java_ref_, success);
}
void FeedReliabilityLoggingBridge::ReportExperiments(
const std::vector<int32_t>& experiment_ids) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_FeedReliabilityLoggingBridge_reportExperiments(env, java_ref_,
experiment_ids);
}
void FeedReliabilityLoggingBridge::Destroy(JNIEnv* env) {
delete this;
}
} // namespace android
} // namespace feed