| // 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 |