Wire up a tracer for Android IP Protection Auth client library
This CL adds the first version of the IP Protection auth client library and tests the end to end data flow by mocking the auth service. An Android instrumentation test is added to run the test. In this initial version, the IPC methods just respond with the same payload that is passed in the request. Context: As part of IP Protection in Android, WebView and Cronet needs to request for authentication tokens from a system provided Android service in order to talk to the IP Protection proxy server. This client library provides a wrapper that handles the IPC to this authentication service. Currently, this component is intended to be used by both WebView and Cronet. Test: "autoninja -C out/Default ip_protection_auth_test_apk && out/Default/bin/run_ip_protection_auth_test_apk" Bug: 1467842 Change-Id: I30f3678a0b42b429938d3ad7b0130b4eff6346c7 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4717487 Reviewed-by: Kinuko Yasuda <kinuko@chromium.org> Reviewed-by: Colin Blundell <blundell@chromium.org> Reviewed-by: Andrew Grieve <agrieve@chromium.org> Commit-Queue: Abhijith Nair <abhijithnair@chromium.org> Cr-Commit-Position: refs/heads/main@{#1203188}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
f2d10cfb2e
commit
3882779f44
BUILD.gn
components/ip_protection_auth
DIR_METADATAOWNERSREADME.md
client
common
javatests
AndroidManifest.xmlBUILD.gnInstrumentationTestAndroidManifest.xml
src
org
chromium
components
ip_protection_auth
mock_service
1
BUILD.gn
1
BUILD.gn
@ -365,6 +365,7 @@ group("gn_all") {
|
||||
"//chrome/android/webapk/shell_apk/prepare_upload_dir:prepare_webapk_shell_upload_dir",
|
||||
"//chrome/test:android_browsertests",
|
||||
"//components:components_junit_tests",
|
||||
"//components/ip_protection_auth/javatests:ip_protection_auth_test_apk",
|
||||
"//content/public/android:content_junit_tests",
|
||||
"//content/shell/android:content_shell_apk",
|
||||
"//device:device_junit_tests",
|
||||
|
13
components/ip_protection_auth/DIR_METADATA
Normal file
13
components/ip_protection_auth/DIR_METADATA
Normal file
@ -0,0 +1,13 @@
|
||||
# Metadata information for this directory.
|
||||
#
|
||||
# For more information on DIR_METADATA files, see:
|
||||
# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
|
||||
#
|
||||
# For the schema of this file, see Metadata message:
|
||||
# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
|
||||
|
||||
team_email: "android-webview-dev@chromium.org"
|
||||
monorail {
|
||||
component: "Mobile>WebView"
|
||||
}
|
||||
os: ANDROID
|
2
components/ip_protection_auth/OWNERS
Normal file
2
components/ip_protection_auth/OWNERS
Normal file
@ -0,0 +1,2 @@
|
||||
abhijithnair@chromium.org
|
||||
edechamps@google.com
|
7
components/ip_protection_auth/README.md
Normal file
7
components/ip_protection_auth/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Android IP Protection Authentication Client Library
|
||||
|
||||
As part of IP Protection in Android, Android components like WebView and Cronet
|
||||
needs to request for authentication tokens from a system provided
|
||||
Android service in order to talk to the IP Protection proxy server.
|
||||
This client library provides a wrapper that handles the IPC to this
|
||||
authentication service.
|
18
components/ip_protection_auth/client/BUILD.gn
Normal file
18
components/ip_protection_auth/client/BUILD.gn
Normal file
@ -0,0 +1,18 @@
|
||||
# Copyright 2023 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//build/config/android/config.gni")
|
||||
import("//build/config/android/rules.gni")
|
||||
|
||||
android_library("ip_protection_auth_client_java") {
|
||||
sources = [ "java/src/org/chromium/components/ip_protection_auth/IpProtectionAuthClient.java" ]
|
||||
deps = [
|
||||
"//components/ip_protection_auth/common/aidl:ip_protection_aidl_java",
|
||||
"//components/ip_protection_auth/common/proto:ip_protection_auth_proto_java",
|
||||
"//third_party/android_deps:com_google_code_findbugs_jsr305_java",
|
||||
"//third_party/android_deps:com_google_errorprone_error_prone_annotations_java",
|
||||
"//third_party/android_deps:protobuf_lite_runtime_java",
|
||||
"//third_party/androidx:androidx_annotation_annotation_java",
|
||||
]
|
||||
}
|
214
components/ip_protection_auth/client/java/src/org/chromium/components/ip_protection_auth/IpProtectionAuthClient.java
Normal file
214
components/ip_protection_auth/client/java/src/org/chromium/components/ip_protection_auth/IpProtectionAuthClient.java
Normal file
@ -0,0 +1,214 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package org.chromium.components.ip_protection_auth;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.google.errorprone.annotations.DoNotCall;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.chromium.components.ip_protection_auth.common.IIpProtectionAuthAndSignCallback;
|
||||
import org.chromium.components.ip_protection_auth.common.IIpProtectionAuthService;
|
||||
import org.chromium.components.ip_protection_auth.common.IIpProtectionGetInitialDataCallback;
|
||||
import org.chromium.components.ip_protection_auth.common.proto.IpProtectionAuthProtos.AuthAndSignRequest;
|
||||
import org.chromium.components.ip_protection_auth.common.proto.IpProtectionAuthProtos.AuthAndSignResponse;
|
||||
import org.chromium.components.ip_protection_auth.common.proto.IpProtectionAuthProtos.GetInitialDataRequest;
|
||||
import org.chromium.components.ip_protection_auth.common.proto.IpProtectionAuthProtos.GetInitialDataResponse;
|
||||
|
||||
/**
|
||||
* Client interface for the IP Protection Auth service.
|
||||
*
|
||||
* The methods in this class are thread-safe (except for close() which should not be called
|
||||
* concurrently with other methods).
|
||||
*
|
||||
* TODO(abhijithnair): Update documentation once production ready.
|
||||
* DO NOT DEPEND. CURRENTLY UNDER DEVELOPMENT.
|
||||
*/
|
||||
public final class IpProtectionAuthClient implements AutoCloseable {
|
||||
// Only used for testing.
|
||||
private static final String IP_PROTECTION_AUTH_STUB_SERVICE_NAME =
|
||||
"org.chromium.components.ip_protection_auth.mock_service.IpProtectionAuthServiceMock";
|
||||
|
||||
// mService being null signifies that the object has been closed by calling close().
|
||||
@Nullable
|
||||
private IIpProtectionAuthService mService;
|
||||
// We need to store this to unbind from the service.
|
||||
@Nullable
|
||||
private ConnectionSetup mConnection;
|
||||
|
||||
private static final class ConnectionSetup implements ServiceConnection {
|
||||
private final IpProtectionAuthServiceCallback mCallback;
|
||||
private final Context mContext;
|
||||
|
||||
ConnectionSetup(
|
||||
@NonNull Context context, @NonNull IpProtectionAuthServiceCallback callback) {
|
||||
mContext = context;
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
|
||||
IpProtectionAuthClient ipProtectionClient = new IpProtectionAuthClient(
|
||||
this, IIpProtectionAuthService.Stub.asInterface(iBinder));
|
||||
mCallback.onResult(ipProtectionClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName componentName) {
|
||||
mContext.unbindService(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindingDied(ComponentName name) {
|
||||
mContext.unbindService(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNullBinding(ComponentName name) {
|
||||
mContext.unbindService(this);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class IIpProtectionGetInitialDataCallbackStub
|
||||
extends IIpProtectionGetInitialDataCallback.Stub {
|
||||
private final GetInitialDataCallback mCallback;
|
||||
|
||||
IIpProtectionGetInitialDataCallbackStub(GetInitialDataCallback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportResult(byte[] bytes) {
|
||||
try {
|
||||
mCallback.onResult(GetInitialDataResponse.parser().parseFrom(bytes));
|
||||
} catch (InvalidProtocolBufferException ex) {
|
||||
// TODO(abhijithnair): Handle this case correctly.
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportError(byte[] bytes) {
|
||||
mCallback.onError(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class IIpProtectionAuthAndSignCallbackStub
|
||||
extends IIpProtectionAuthAndSignCallback.Stub {
|
||||
private final AuthAndSignCallback mCallback;
|
||||
|
||||
IIpProtectionAuthAndSignCallbackStub(AuthAndSignCallback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportResult(byte[] bytes) {
|
||||
try {
|
||||
mCallback.onResult(AuthAndSignResponse.parser().parseFrom(bytes));
|
||||
} catch (InvalidProtocolBufferException ex) {
|
||||
// TODO(abhijithnair): Handle this case correctly.
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportError(byte[] bytes) {
|
||||
mCallback.onError(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IpProtectionAuthServiceCallback {
|
||||
void onResult(IpProtectionAuthClient client);
|
||||
|
||||
void onError(String error);
|
||||
}
|
||||
|
||||
public interface GetInitialDataCallback {
|
||||
// TODO(abhijithnair): Consider using a non-proto generated class.
|
||||
void onResult(GetInitialDataResponse result);
|
||||
|
||||
// TODO(abhijithnair): Change to using a error specific class.
|
||||
void onError(byte[] error);
|
||||
}
|
||||
|
||||
public interface AuthAndSignCallback {
|
||||
// TODO(abhijithnair): Consider using a non-proto generated class.
|
||||
void onResult(AuthAndSignResponse result);
|
||||
|
||||
// TODO(abhijithnair): Change to using a error specific class.
|
||||
void onError(byte[] error);
|
||||
}
|
||||
|
||||
IpProtectionAuthClient(@NonNull ConnectionSetup connectionSetup,
|
||||
@NonNull IIpProtectionAuthService ipProtectionAuthService) {
|
||||
mConnection = connectionSetup;
|
||||
mService = ipProtectionAuthService;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static void createConnectedInstanceForTestingAsync(
|
||||
@NonNull Context context, @NonNull IpProtectionAuthServiceCallback callback) {
|
||||
ComponentName componentName =
|
||||
new ComponentName(context, IP_PROTECTION_AUTH_STUB_SERVICE_NAME);
|
||||
Intent intent = new Intent();
|
||||
intent.setComponent(componentName);
|
||||
ConnectionSetup connectionSetup = new ConnectionSetup(context, callback);
|
||||
context.bindService(intent, connectionSetup, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
@DoNotCall
|
||||
public static void createConnectedInstance(
|
||||
@NonNull Context context, @NonNull IpProtectionAuthServiceCallback callback) {
|
||||
// TODO(abhijithnair): Implement!
|
||||
throw new UnsupportedOperationException("unimplemented");
|
||||
}
|
||||
|
||||
public void getInitialData(GetInitialDataRequest request, GetInitialDataCallback callback) {
|
||||
if (mService == null) {
|
||||
// This denotes a coding error by the caller so it makes sense to throw an unchecked
|
||||
// exception.
|
||||
throw new IllegalStateException("Already closed");
|
||||
}
|
||||
|
||||
IIpProtectionGetInitialDataCallbackStub callbackStub =
|
||||
new IIpProtectionGetInitialDataCallbackStub(callback);
|
||||
try {
|
||||
mService.getInitialData(request.toByteArray(), callbackStub);
|
||||
} catch (RemoteException ex) {
|
||||
// TODO(abhijithnair): Handle this case correctly.
|
||||
}
|
||||
}
|
||||
|
||||
public void authAndSign(AuthAndSignRequest request, AuthAndSignCallback callback) {
|
||||
if (mService == null) {
|
||||
// This denotes a coding error by the caller so it makes sense to throw an unchecked
|
||||
// exception.
|
||||
throw new IllegalStateException("Already closed");
|
||||
}
|
||||
IIpProtectionAuthAndSignCallbackStub callbackStub =
|
||||
new IIpProtectionAuthAndSignCallbackStub(callback);
|
||||
try {
|
||||
mService.authAndSign(request.toByteArray(), callbackStub);
|
||||
} catch (RemoteException ex) {
|
||||
// TODO(abhijithnair): Handle this case correctly.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mConnection.mContext.unbindService(mConnection);
|
||||
mConnection = null;
|
||||
mService = null;
|
||||
}
|
||||
}
|
19
components/ip_protection_auth/common/aidl/BUILD.gn
Normal file
19
components/ip_protection_auth/common/aidl/BUILD.gn
Normal file
@ -0,0 +1,19 @@
|
||||
# Copyright 2023 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//build/config/android/rules.gni")
|
||||
import("//testing/test.gni")
|
||||
|
||||
android_aidl("ip_protection_aidl") {
|
||||
import_include = [ "src" ]
|
||||
sources = [
|
||||
"src/org/chromium/components/ip_protection_auth/common/IIpProtectionAuthAndSignCallback.aidl",
|
||||
"src/org/chromium/components/ip_protection_auth/common/IIpProtectionAuthService.aidl",
|
||||
"src/org/chromium/components/ip_protection_auth/common/IIpProtectionGetInitialDataCallback.aidl",
|
||||
]
|
||||
}
|
||||
|
||||
android_library("ip_protection_aidl_java") {
|
||||
srcjar_deps = [ ":ip_protection_aidl" ]
|
||||
}
|
15
components/ip_protection_auth/common/aidl/src/org/chromium/components/ip_protection_auth/common/IIpProtectionAuthAndSignCallback.aidl
Normal file
15
components/ip_protection_auth/common/aidl/src/org/chromium/components/ip_protection_auth/common/IIpProtectionAuthAndSignCallback.aidl
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package org.chromium.components.ip_protection_auth.common;
|
||||
|
||||
/**
|
||||
* Used for communicating the result of authAndSign() to the caller.
|
||||
*/
|
||||
oneway interface IIpProtectionAuthAndSignCallback {
|
||||
// Parameter is the serialized form of AuthAndSignResponse proto
|
||||
void reportResult(in byte[] response) = 0;
|
||||
// Parameter is the serialized form of AuthAndSignError proto
|
||||
void reportError(in byte[] error) = 1;
|
||||
}
|
18
components/ip_protection_auth/common/aidl/src/org/chromium/components/ip_protection_auth/common/IIpProtectionAuthService.aidl
Normal file
18
components/ip_protection_auth/common/aidl/src/org/chromium/components/ip_protection_auth/common/IIpProtectionAuthService.aidl
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package org.chromium.components.ip_protection_auth.common;
|
||||
|
||||
import org.chromium.components.ip_protection_auth.common.IIpProtectionAuthAndSignCallback;
|
||||
import org.chromium.components.ip_protection_auth.common.IIpProtectionGetInitialDataCallback;
|
||||
|
||||
/**
|
||||
* Used for conversing with the IP Protection Service.
|
||||
*/
|
||||
interface IIpProtectionAuthService {
|
||||
// Request should be the serialized form of GetInitialDataRequest proto
|
||||
void getInitialData(in byte[] request, in IIpProtectionGetInitialDataCallback callback) = 0;
|
||||
// Request should be the serialized form of AuthAndSignRequest proto
|
||||
void authAndSign(in byte[] request, in IIpProtectionAuthAndSignCallback callback) = 1;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package org.chromium.components.ip_protection_auth.common;
|
||||
|
||||
/**
|
||||
* Used for communicating the result of getInitialData() to the caller.
|
||||
*/
|
||||
oneway interface IIpProtectionGetInitialDataCallback {
|
||||
// Parameter is the serialized form of GetInitialDataResponse proto
|
||||
void reportResult(in byte[] response) = 0;
|
||||
// Parameter is the serialized form of GetInitialDataError proto
|
||||
void reportError(in byte[] error) = 1;
|
||||
}
|
2
components/ip_protection_auth/common/aidl/src/org/chromium/components/ip_protection_auth/common/OWNERS
Normal file
2
components/ip_protection_auth/common/aidl/src/org/chromium/components/ip_protection_auth/common/OWNERS
Normal file
@ -0,0 +1,2 @@
|
||||
per-file *.aidl=set noparent
|
||||
per-file *.aidl=file://ipc/SECURITY_OWNERS
|
11
components/ip_protection_auth/common/proto/BUILD.gn
Normal file
11
components/ip_protection_auth/common/proto/BUILD.gn
Normal file
@ -0,0 +1,11 @@
|
||||
# Copyright 2023 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//build/config/android/rules.gni")
|
||||
import("//third_party/protobuf/proto_library.gni")
|
||||
|
||||
proto_java_library("ip_protection_auth_proto_java") {
|
||||
proto_path = "."
|
||||
sources = [ "ip_protection_auth.proto" ]
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
syntax = "proto3";
|
||||
package org.chromium.components.ip_protection_auth.common.proto;
|
||||
|
||||
option optimize_for = LITE_RUNTIME; // TODO(crbug/800281): Remove this after proto 4.0
|
||||
option java_package = "org.chromium.components.ip_protection_auth.common.proto";
|
||||
option java_outer_classname = "IpProtectionAuthProtos";
|
||||
|
||||
// TODO(abhijithnair): Currently this is a sample used to get the end to end
|
||||
// data flow set up. This will be modified with real fields.
|
||||
// Next tag: 2
|
||||
message GetInitialDataRequest {
|
||||
string test_payload = 1;
|
||||
}
|
||||
|
||||
// TODO(abhijithnair): Currently this is a sample used to get the end to end
|
||||
// data flow set up. This will be modified with real fields.
|
||||
// Next tag: 2
|
||||
message GetInitialDataResponse {
|
||||
string test_payload = 1;
|
||||
}
|
||||
|
||||
// TODO(abhijithnair): Currently this is a sample used to get the end to end
|
||||
// data flow set up. This will be modified with real fields.
|
||||
// Next tag: 2
|
||||
message AuthAndSignRequest {
|
||||
string test_payload = 1;
|
||||
}
|
||||
|
||||
// TODO(abhijithnair): Currently this is a sample used to get the end to end
|
||||
// data flow set up. This will be modified with real fields.
|
||||
// Next tag: 2
|
||||
message AuthAndSignResponse {
|
||||
string test_payload = 1;
|
||||
}
|
12
components/ip_protection_auth/javatests/AndroidManifest.xml
Normal file
12
components/ip_protection_auth/javatests/AndroidManifest.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2023 The Chromium Authors
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file. -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.chromium.components.ip_protection_auth">
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<application android:label="Ip Protection Auth">
|
||||
<service android:name="org.chromium.components.ip_protection_auth.mock_service.IpProtectionAuthServiceMock"
|
||||
android:exported="true" />
|
||||
</application>
|
||||
</manifest>
|
30
components/ip_protection_auth/javatests/BUILD.gn
Normal file
30
components/ip_protection_auth/javatests/BUILD.gn
Normal file
@ -0,0 +1,30 @@
|
||||
# Copyright 2023 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//build/config/android/rules.gni")
|
||||
import("//testing/test.gni")
|
||||
|
||||
instrumentation_test_apk("ip_protection_auth_test_apk") {
|
||||
apk_name = "IpProtectionAuthTest"
|
||||
apk_under_test = ":ip_protection_auth_apk"
|
||||
android_manifest = "InstrumentationTestAndroidManifest.xml"
|
||||
sources = [ "src/org/chromium/components/ip_protection_auth/test/IpProtectionAuthTest.java" ]
|
||||
deps = [
|
||||
"../client:ip_protection_auth_client_java",
|
||||
"//base:base_java_test_support",
|
||||
"//components/ip_protection_auth/common/proto:ip_protection_auth_proto_java",
|
||||
"//third_party/android_deps:protobuf_lite_runtime_java",
|
||||
"//third_party/androidx:androidx_test_core_java",
|
||||
"//third_party/androidx:androidx_test_ext_junit_java",
|
||||
"//third_party/androidx:androidx_test_runner_java",
|
||||
"//third_party/google-truth:google_truth_java",
|
||||
"//third_party/junit:junit",
|
||||
]
|
||||
}
|
||||
|
||||
android_apk("ip_protection_auth_apk") {
|
||||
apk_name = "IpProtectionAuth"
|
||||
android_manifest = "AndroidManifest.xml"
|
||||
deps = [ "../mock_service:ip_protection_auth_service_mock_java" ]
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2023 The Chromium Authors
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file. -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.chromium.components.ip_protection_auth.test">
|
||||
<instrumentation android:name="org.chromium.base.test.BaseChromiumAndroidJUnitRunner"
|
||||
android:targetPackage="org.chromium.components.ip_protection_auth"
|
||||
android:label="Tests for org.chromium.chromium.components.ip_protection_auth"/>
|
||||
<uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
|
||||
</manifest>
|
112
components/ip_protection_auth/javatests/src/org/chromium/components/ip_protection_auth/test/IpProtectionAuthTest.java
Normal file
112
components/ip_protection_auth/javatests/src/org/chromium/components/ip_protection_auth/test/IpProtectionAuthTest.java
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package org.chromium.components.ip_protection_auth.test;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.ConditionVariable;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.MediumTest;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.chromium.base.test.util.Batch;
|
||||
import org.chromium.components.ip_protection_auth.IpProtectionAuthClient;
|
||||
import org.chromium.components.ip_protection_auth.common.proto.IpProtectionAuthProtos.AuthAndSignRequest;
|
||||
import org.chromium.components.ip_protection_auth.common.proto.IpProtectionAuthProtos.AuthAndSignResponse;
|
||||
import org.chromium.components.ip_protection_auth.common.proto.IpProtectionAuthProtos.GetInitialDataRequest;
|
||||
import org.chromium.components.ip_protection_auth.common.proto.IpProtectionAuthProtos.GetInitialDataResponse;
|
||||
|
||||
@MediumTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@Batch(Batch.UNIT_TESTS)
|
||||
public final class IpProtectionAuthTest {
|
||||
IpProtectionAuthClient mIpProtectionClient;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
|
||||
final ConditionVariable conditionVariable = new ConditionVariable();
|
||||
IpProtectionAuthClient.IpProtectionAuthServiceCallback callback =
|
||||
new IpProtectionAuthClient.IpProtectionAuthServiceCallback() {
|
||||
@Override
|
||||
public void onResult(IpProtectionAuthClient client) {
|
||||
mIpProtectionClient = client;
|
||||
conditionVariable.open();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
fail("onError should not be called");
|
||||
}
|
||||
};
|
||||
IpProtectionAuthClient.createConnectedInstanceForTestingAsync(context, callback);
|
||||
assertThat(conditionVariable.block(5000)).isTrue();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mIpProtectionClient.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInitialDataTest() throws Exception {
|
||||
final ConditionVariable conditionVariable = new ConditionVariable();
|
||||
// Using a 1-element array so that the reference is final and can be passed into the lambda.
|
||||
final GetInitialDataResponse[] getInitialDataResponse = new GetInitialDataResponse[1];
|
||||
IpProtectionAuthClient.GetInitialDataCallback getInitialDataCallback =
|
||||
new IpProtectionAuthClient.GetInitialDataCallback() {
|
||||
@Override
|
||||
public void onResult(GetInitialDataResponse response) {
|
||||
getInitialDataResponse[0] = response;
|
||||
conditionVariable.open();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(byte[] error) {
|
||||
fail("onError should not be called");
|
||||
}
|
||||
};
|
||||
GetInitialDataRequest request =
|
||||
GetInitialDataRequest.newBuilder().setTestPayload("get initial data").build();
|
||||
mIpProtectionClient.getInitialData(request, getInitialDataCallback);
|
||||
assertThat(conditionVariable.block(5000)).isTrue();
|
||||
assertThat(getInitialDataResponse[0].getTestPayload()).isEqualTo("get initial data");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authAndSignTest() throws Exception {
|
||||
final ConditionVariable conditionVariable = new ConditionVariable();
|
||||
// Using a 1-element array so that the reference is final and can be passed into the lambda.
|
||||
final AuthAndSignResponse[] authAndSignResponse = new AuthAndSignResponse[1];
|
||||
IpProtectionAuthClient.AuthAndSignCallback authAndSignCallback =
|
||||
new IpProtectionAuthClient.AuthAndSignCallback() {
|
||||
@Override
|
||||
public void onResult(AuthAndSignResponse response) {
|
||||
authAndSignResponse[0] = response;
|
||||
conditionVariable.open();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(byte[] bytes) {
|
||||
fail("onError should not be called");
|
||||
}
|
||||
};
|
||||
AuthAndSignRequest authAndSignRequest =
|
||||
AuthAndSignRequest.newBuilder().setTestPayload("auth and sign").build();
|
||||
mIpProtectionClient.authAndSign(authAndSignRequest, authAndSignCallback);
|
||||
assertThat(conditionVariable.block(5000)).isTrue();
|
||||
assertThat(authAndSignResponse[0].getTestPayload()).isEqualTo("auth and sign");
|
||||
}
|
||||
}
|
13
components/ip_protection_auth/mock_service/BUILD.gn
Normal file
13
components/ip_protection_auth/mock_service/BUILD.gn
Normal file
@ -0,0 +1,13 @@
|
||||
import("//build/config/android/config.gni")
|
||||
import("//build/config/android/rules.gni")
|
||||
|
||||
android_library("ip_protection_auth_service_mock_java") {
|
||||
sources = [ "java/src/org/chromium/components/ip_protection_auth/mock_service/IpProtectionAuthServiceMock.java" ]
|
||||
|
||||
deps = [
|
||||
"//components/ip_protection_auth/common/aidl:ip_protection_aidl_java",
|
||||
"//components/ip_protection_auth/common/proto:ip_protection_auth_proto_java",
|
||||
"//third_party/android_deps:protobuf_lite_runtime_java",
|
||||
"//third_party/androidx:androidx_annotation_annotation_java",
|
||||
]
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package org.chromium.components.ip_protection_auth.mock_service;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.chromium.components.ip_protection_auth.common.IIpProtectionAuthAndSignCallback;
|
||||
import org.chromium.components.ip_protection_auth.common.IIpProtectionAuthService;
|
||||
import org.chromium.components.ip_protection_auth.common.IIpProtectionGetInitialDataCallback;
|
||||
import org.chromium.components.ip_protection_auth.common.proto.IpProtectionAuthProtos.AuthAndSignRequest;
|
||||
import org.chromium.components.ip_protection_auth.common.proto.IpProtectionAuthProtos.AuthAndSignResponse;
|
||||
import org.chromium.components.ip_protection_auth.common.proto.IpProtectionAuthProtos.GetInitialDataRequest;
|
||||
import org.chromium.components.ip_protection_auth.common.proto.IpProtectionAuthProtos.GetInitialDataResponse;
|
||||
|
||||
/**
|
||||
* Mock implementation of the IP Protection Auth Service
|
||||
*/
|
||||
public final class IpProtectionAuthServiceMock extends Service {
|
||||
private static final String TAG = "IpProtectionAuthServiceMock";
|
||||
private final IIpProtectionAuthService.Stub mBinder = new IIpProtectionAuthService.Stub() {
|
||||
// TODO(abhijithnair): Currently this method just passes the same request byte[] back as the
|
||||
// result. Use a mock result instead.
|
||||
@Override
|
||||
public void getInitialData(byte[] bytes, IIpProtectionGetInitialDataCallback callback) {
|
||||
try {
|
||||
GetInitialDataRequest request = GetInitialDataRequest.parser().parseFrom(bytes);
|
||||
GetInitialDataResponse response = GetInitialDataResponse.newBuilder()
|
||||
.setTestPayload(request.getTestPayload())
|
||||
.build();
|
||||
callback.reportResult(response.toByteArray());
|
||||
} catch (RemoteException ex) {
|
||||
// TODO(abhijithnair): Handle this exception correctly.
|
||||
throw new RuntimeException(ex);
|
||||
} catch (InvalidProtocolBufferException ex) {
|
||||
// TODO(abhijithnair): Handle this exception correctly.
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(abhijithnair): Currently this method just passes the same request byte[] back as the
|
||||
// result. Use a mock result instead.
|
||||
@Override
|
||||
public void authAndSign(byte[] bytes, IIpProtectionAuthAndSignCallback callback) {
|
||||
try {
|
||||
AuthAndSignRequest request = AuthAndSignRequest.parser().parseFrom(bytes);
|
||||
AuthAndSignResponse response = AuthAndSignResponse.newBuilder()
|
||||
.setTestPayload(request.getTestPayload())
|
||||
.build();
|
||||
callback.reportResult(response.toByteArray());
|
||||
} catch (RemoteException ex) {
|
||||
// TODO(abhijithnair): Handle this exception correctly.
|
||||
throw new RuntimeException(ex);
|
||||
} catch (InvalidProtocolBufferException ex) {
|
||||
// TODO(abhijithnair): Handle this exception correctly.
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user