diff options
17 files changed, 558 insertions, 228 deletions
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/policy/PolicyManager.java b/chrome/android/java/src/org/chromium/chrome/browser/policy/PolicyManager.java index 9856dba..d4f1e20 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/policy/PolicyManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/policy/PolicyManager.java @@ -8,6 +8,7 @@ import android.os.Bundle; import org.chromium.base.CalledByNative; import org.chromium.base.ThreadUtils; +import org.chromium.policy.PolicyConverter; import java.util.ArrayList; import java.util.List; @@ -19,6 +20,7 @@ import java.util.List; public class PolicyManager { private long mNativePolicyManager; + private PolicyConverter mPolicyConverter; private final List<PolicyProvider> mPolicyProviders = new ArrayList<>(); private final List<Bundle> mCachedPolicies = new ArrayList<>(); private final List<PolicyChangeListener> mPolicyChangeListeners = new ArrayList<>(); @@ -26,6 +28,7 @@ public class PolicyManager { public void initializeNative() { ThreadUtils.assertOnUiThread(); mNativePolicyManager = nativeInit(); + mPolicyConverter = nativeCreatePolicyConverter(mNativePolicyManager); } /** @@ -51,6 +54,7 @@ public class PolicyManager { nativeDestroy(mNativePolicyManager); mNativePolicyManager = 0; + mPolicyConverter = null; } void onSettingsAvailable(int source, Bundle newSettings) { @@ -61,24 +65,7 @@ public class PolicyManager { } for (Bundle settings : mCachedPolicies) { for (String key : settings.keySet()) { - Object value = settings.get(key); - if (value instanceof Boolean) { - nativeSetPolicyBoolean(mNativePolicyManager, key, (Boolean) value); - continue; - } - if (value instanceof String) { - nativeSetPolicyString(mNativePolicyManager, key, (String) value); - continue; - } - if (value instanceof Integer) { - nativeSetPolicyInteger(mNativePolicyManager, key, (Integer) value); - continue; - } - if (value instanceof String[]) { - nativeSetPolicyStringArray(mNativePolicyManager, key, (String[]) value); - continue; - } - assert false : "Invalid setting " + value + " for key " + key; + mPolicyConverter.setPolicy(key, settings.get(key)); } } nativeFlushPolicies(mNativePolicyManager); @@ -121,15 +108,7 @@ public class PolicyManager { } private native long nativeInit(); + private native PolicyConverter nativeCreatePolicyConverter(long nativePolicyManager); private native void nativeDestroy(long nativePolicyManager); - - private native void nativeSetPolicyBoolean( - long nativePolicyManager, String policyKey, boolean value); - private native void nativeSetPolicyInteger( - long nativePolicyManager, String policyKey, int value); - private native void nativeSetPolicyString( - long nativePolicyManager, String policyKey, String value); - private native void nativeSetPolicyStringArray( - long nativePolicyManager, String policyKey, String[] value); private native void nativeFlushPolicies(long nativePolicyManager); } diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc index 3c4b02b..44de8f2 100644 --- a/chrome/browser/android/chrome_jni_registrar.cc +++ b/chrome/browser/android/chrome_jni_registrar.cc @@ -132,6 +132,7 @@ #include "components/gcm_driver/android/component_jni_registrar.h" #include "components/invalidation/impl/android/component_jni_registrar.h" #include "components/navigation_interception/component_jni_registrar.h" +#include "components/policy/core/browser/android/component_jni_registrar.h" #include "components/safe_json/android/component_jni_registrar.h" #include "components/service_tab_launcher/component_jni_registrar.h" #include "components/variations/android/component_jni_registrar.h" @@ -154,6 +155,7 @@ static base::android::RegistrationMethod kChromeRegisteredMethods[] = { {"Invalidation", invalidation::android::RegisterInvalidationJni}, {"NavigationInterception", navigation_interception::RegisterNavigationInterceptionJni}, + {"Policy", policy::android::RegisterPolicy}, {"SafeJson", safe_json::android::RegisterSafeJsonJni}, {"WebContentsDelegateAndroid", web_contents_delegate_android::RegisterWebContentsDelegateAndroidJni}, diff --git a/chrome/browser/android/policy/policy_manager.cc b/chrome/browser/android/policy/policy_manager.cc index 62dbf405..696f3a2 100644 --- a/chrome/browser/android/policy/policy_manager.cc +++ b/chrome/browser/android/policy/policy_manager.cc @@ -5,25 +5,19 @@ #include "chrome/browser/android/policy/policy_manager.h" #include "base/android/jni_android.h" -#include "base/android/jni_array.h" -#include "base/android/jni_string.h" -#include "base/bind.h" -#include "base/json/json_reader.h" -#include "base/prefs/pref_service.h" -#include "base/strings/string_number_conversions.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/common/pref_names.h" +#include "chrome/browser/browser_process_platform_part.h" +#include "components/policy/core/browser/android/policy_converter.h" #include "components/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/common/policy_provider_android.h" +#include "components/policy/core/common/schema.h" #include "jni/PolicyManager_jni.h" using base::android::AttachCurrentThread; -using base::android::ConvertJavaStringToUTF8; +using base::android::ScopedJavaLocalRef; PolicyManager::PolicyManager(JNIEnv* env, jobject obj) - : weak_java_policy_manager_(env, obj), - policy_bundle_(new policy::PolicyBundle) { + : weak_java_policy_manager_(env, obj) { policy_provider_ = static_cast<policy::PolicyProviderAndroid*>( g_browser_process->browser_policy_connector()->GetPlatformProvider()); policy_provider_->SetDelegate(this); @@ -31,6 +25,13 @@ PolicyManager::PolicyManager(JNIEnv* env, jobject obj) PolicyManager::~PolicyManager() {} +ScopedJavaLocalRef<jobject> PolicyManager::CreatePolicyConverter(JNIEnv* env, + jobject obj) { + policy_converter_.reset(new policy::android::PolicyConverter( + policy_provider_->GetChromeSchema())); + return ScopedJavaLocalRef<jobject>(policy_converter_->GetJavaObject()); +} + void PolicyManager::RefreshPolicies() { JNIEnv* env = AttachCurrentThread(); Java_PolicyManager_refreshPolicies( @@ -38,154 +39,23 @@ void PolicyManager::RefreshPolicies() { } void PolicyManager::PolicyProviderShutdown() { - policy_provider_ = NULL; -} - -void PolicyManager::SetPolicyBoolean(JNIEnv* env, - jobject obj, - jstring policyKey, - jboolean value) { - SetPolicyValue(ConvertJavaStringToUTF8(env, policyKey), - new base::FundamentalValue(static_cast<bool>(value))); -} - -void PolicyManager::SetPolicyInteger(JNIEnv* env, - jobject obj, - jstring policyKey, - jint value) { - SetPolicyValue(ConvertJavaStringToUTF8(env, policyKey), - new base::FundamentalValue(static_cast<int>(value))); -} - -void PolicyManager::SetPolicyString(JNIEnv* env, - jobject obj, - jstring policyKey, - jstring value) { - SetPolicyValue(ConvertJavaStringToUTF8(env, policyKey), - new base::StringValue(ConvertJavaStringToUTF8(env, value))); -} - -void PolicyManager::SetPolicyStringArray(JNIEnv* env, - jobject obj, - jstring policyKey, - jobjectArray array) { - std::vector<base::string16> string_vector; - base::android::AppendJavaStringArrayToStringVector(env, array, - &string_vector); - base::ListValue* list_values = new base::ListValue(); - list_values->AppendStrings(string_vector); - SetPolicyValue(ConvertJavaStringToUTF8(env, policyKey), list_values); + policy_provider_ = nullptr; } void PolicyManager::FlushPolicies(JNIEnv* env, jobject obj) { if (!policy_provider_) return; - policy_provider_->SetPolicies(policy_bundle_.Pass()); - policy_bundle_.reset(new policy::PolicyBundle); + policy_provider_->SetPolicies(policy_converter_->GetPolicyBundle()); } void PolicyManager::Destroy(JNIEnv* env, jobject obj) { if (policy_provider_) - policy_provider_->SetDelegate(NULL); + policy_provider_->SetDelegate(nullptr); delete this; } -// static -base::Value* PolicyManager::ConvertValueToSchema(base::Value* raw_value, - const policy::Schema& schema) { - scoped_ptr<base::Value> value(raw_value); - - if (!schema.valid()) - return value.release(); - - switch (schema.type()) { - case base::Value::TYPE_NULL: - return base::Value::CreateNullValue().release(); - - case base::Value::TYPE_BOOLEAN: { - std::string string_value; - if (value->GetAsString(&string_value)) { - if (string_value.compare("true") == 0) - return new base::FundamentalValue(true); - - if (string_value.compare("false") == 0) - return new base::FundamentalValue(false); - - return value.release(); - } - int int_value = 0; - if (value->GetAsInteger(&int_value)) - return new base::FundamentalValue(int_value != 0); - - return value.release(); - } - - case base::Value::TYPE_INTEGER: { - std::string string_value; - if (value->GetAsString(&string_value)) { - int int_value = 0; - if (base::StringToInt(string_value, &int_value)) - return new base::FundamentalValue(int_value); - } - return value.release(); - } - - case base::Value::TYPE_DOUBLE: { - std::string string_value; - if (value->GetAsString(&string_value)) { - double double_value = 0; - if (base::StringToDouble(string_value, &double_value)) - return new base::FundamentalValue(double_value); - } - return value.release(); - } - - // String can't be converted from other types. - case base::Value::TYPE_STRING: { - return value.release(); - } - - // Binary is not a valid schema type. - case base::Value::TYPE_BINARY: { - NOTREACHED(); - return NULL; - } - - // Complex types have to be deserialized from JSON. - case base::Value::TYPE_DICTIONARY: - case base::Value::TYPE_LIST: { - std::string string_value; - if (value->GetAsString(&string_value)) { - scoped_ptr<base::Value> decoded_value = - base::JSONReader::Read(string_value); - if (decoded_value) - return decoded_value.release(); - } - return value.release(); - } - } - - NOTREACHED(); - return NULL; -} - -void PolicyManager::SetPolicyValue(const std::string& key, base::Value* value) { - if (!policy_provider_) - return; - - policy::Schema schema = - policy_provider_->GetChromeSchema()->GetKnownProperty(key); - - policy::PolicyNamespace ns(policy::POLICY_DOMAIN_CHROME, std::string()); - policy_bundle_->Get(ns).Set(key, - policy::POLICY_LEVEL_MANDATORY, - policy::POLICY_SCOPE_MACHINE, - ConvertValueToSchema(value, schema), - NULL); -} - static jlong Init(JNIEnv* env, jobject obj) { return reinterpret_cast<intptr_t>(new PolicyManager(env, obj)); } diff --git a/chrome/browser/android/policy/policy_manager.h b/chrome/browser/android/policy/policy_manager.h index a24650d..21c72be 100644 --- a/chrome/browser/android/policy/policy_manager.h +++ b/chrome/browser/android/policy/policy_manager.h @@ -8,52 +8,33 @@ #include <jni.h> #include "base/android/jni_weak_ref.h" -#include "components/policy/core/common/policy_bundle.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" #include "components/policy/core/common/policy_provider_android_delegate.h" namespace policy { class PolicyProviderAndroid; -class Schema; +namespace android { + +class PolicyConverter; + +} // namespace android } // namespace policy class PolicyManager : public policy::PolicyProviderAndroidDelegate { public: PolicyManager(JNIEnv* env, jobject obj); - // Called from Java: - void SetPolicyBoolean(JNIEnv* env, - jobject obj, - jstring policyKey, - jboolean value); - void SetPolicyInteger(JNIEnv* env, - jobject obj, - jstring policyKey, - jint value); - void SetPolicyString(JNIEnv* env, - jobject obj, - jstring policyKey, - jstring value); - void SetPolicyStringArray(JNIEnv* env, - jobject obj, - jstring policyKey, - jobjectArray value); void FlushPolicies(JNIEnv* env, jobject obj); void Destroy(JNIEnv* env, jobject obj); - // Converts the passed in value to the type desired by the schema. If the - // value is not convertible, it is returned unchanged, so the policy system - // can report the error. - // Note that this method will only look at the type of the schema, not at any - // additional restrictions, or the schema for value's items or properties in - // the case of a list or dictionary value. - // This method takes ownership of the passed in value, and the caller takes - // ownership of the return value. - // Public for testing. - static base::Value* ConvertValueToSchema(base::Value* raw_value, - const policy::Schema& schema); + // Creates the native and java |PolicyConverter|, returns the reference to + // the java one. + base::android::ScopedJavaLocalRef<jobject> CreatePolicyConverter(JNIEnv* env, + jobject obj); // PolicyProviderAndroidDelegate: void RefreshPolicies() override; @@ -64,11 +45,9 @@ class PolicyManager : public policy::PolicyProviderAndroidDelegate { JavaObjectWeakGlobalRef weak_java_policy_manager_; - scoped_ptr<policy::PolicyBundle> policy_bundle_; + scoped_ptr<policy::android::PolicyConverter> policy_converter_; policy::PolicyProviderAndroid* policy_provider_; - void SetPolicyValue(const std::string& key, base::Value* value); - DISALLOW_COPY_AND_ASSIGN(PolicyManager); }; diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index ec18baa..069d02a 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -19,7 +19,6 @@ # TODO(newt): move this to test_support_unit? 'browser/android/mock_location_settings.cc', 'browser/android/mock_location_settings.h', - 'browser/android/policy/policy_manager_unittest.cc', 'browser/android/preferences/pref_service_bridge_unittest.cc', 'browser/android/thumbnail/scoped_ptr_expiring_cache_unittest.cc', 'browser/app_controller_mac_unittest.mm', diff --git a/components/components_tests.gyp b/components/components_tests.gyp index e0e1e53..b52326c 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -391,6 +391,7 @@ 'password_manager/core/common/credential_manager_types_unittest.cc', ], 'policy_unittest_sources': [ + 'policy/core/browser/android/policy_converter_unittest.cc', 'policy/core/browser/autofill_policy_handler_unittest.cc', 'policy/core/browser/browser_policy_connector_unittest.cc', 'policy/core/browser/configuration_policy_handler_unittest.cc', diff --git a/components/policy.gypi b/components/policy.gypi index f37d4ce..2302487 100644 --- a/components/policy.gypi +++ b/components/policy.gypi @@ -395,6 +395,18 @@ }, 'includes': [ '../build/java.gypi' ], }, + { + # GN: //components/policy/android:jni_headers + 'target_name': 'policy_jni_headers', + 'type': 'none', + 'sources': [ + 'policy/android/java/src/org/chromium/policy/PolicyConverter.java', + ], + 'variables': { + 'jni_gen_package': 'policy', + }, + 'includes': [ '../build/jni_generator.gypi' ], + }, ], }], ['OS=="win" and target_arch=="ia32" and configuration_policy==1', { diff --git a/components/policy/android/BUILD.gn b/components/policy/android/BUILD.gn index 3f1fae4..9784e36 100644 --- a/components/policy/android/BUILD.gn +++ b/components/policy/android/BUILD.gn @@ -4,10 +4,20 @@ import("//build/config/android/rules.gni") +_jni_sources = [ "java/src/org/chromium/policy/PolicyConverter.java" ] + # GYP: //components/components.gyp:policy_java android_library("policy_java") { deps = [ "//base:base_java", ] - java_files = [ "java/src/org/chromium/policy/AppRestrictionsProvider.java" ] + java_files = [ "java/src/org/chromium/policy/AppRestrictionsProvider.java" ] + + _jni_sources +} + +# GYP: //components/components.gyp:policy_jni_headers +generate_jni("jni_headers") { + visibility = [ "//components/policy/*" ] + sources = _jni_sources + jni_package = "policy" } diff --git a/components/policy/android/java/src/org/chromium/policy/PolicyConverter.java b/components/policy/android/java/src/org/chromium/policy/PolicyConverter.java new file mode 100644 index 0000000..4d4835b8 --- /dev/null +++ b/components/policy/android/java/src/org/chromium/policy/PolicyConverter.java @@ -0,0 +1,69 @@ +// Copyright 2015 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. + +package org.chromium.policy; + +import org.chromium.base.CalledByNative; +import org.chromium.base.JNINamespace; + +/** + * Allows converting Java policies, contained as key/value pairs in {@link android.os.Bundle}s to + * native {@code PolicyBundle}s. + * + * This class is to be used to send key/value pairs to its native equivalent, that can then be used + * to retrieve the native {@code PolicyBundle}. + * + * It should be created by calling {@link #create(long)} from the native code, and sending it back + * to Java. + */ +@JNINamespace("policy::android") +public class PolicyConverter { + private long mNativePolicyConverter; + + private PolicyConverter(long nativePolicyConverter) { + mNativePolicyConverter = nativePolicyConverter; + } + + /** Convert and send the key/value pair for a policy to the native {@code PolicyConverter}. */ + public void setPolicy(String key, Object value) { + assert mNativePolicyConverter != 0; + + if (value instanceof Boolean) { + nativeSetPolicyBoolean(mNativePolicyConverter, key, (Boolean) value); + return; + } + if (value instanceof String) { + nativeSetPolicyString(mNativePolicyConverter, key, (String) value); + return; + } + if (value instanceof Integer) { + nativeSetPolicyInteger(mNativePolicyConverter, key, (Integer) value); + return; + } + if (value instanceof String[]) { + nativeSetPolicyStringArray(mNativePolicyConverter, key, (String[]) value); + return; + } + assert false : "Invalid setting " + value + " for key " + key; + } + + @CalledByNative + private static PolicyConverter create(long nativePolicyConverter) { + return new PolicyConverter(nativePolicyConverter); + } + + @CalledByNative + private void onNativeDestroyed() { + mNativePolicyConverter = 0; + } + + private native void nativeSetPolicyBoolean( + long nativePolicyConverter, String policyKey, boolean value); + private native void nativeSetPolicyInteger( + long nativePolicyConverter, String policyKey, int value); + private native void nativeSetPolicyString( + long nativePolicyConverter, String policyKey, String value); + private native void nativeSetPolicyStringArray( + long nativePolicyConverter, String policyKey, String[] value); +} diff --git a/components/policy/core/browser/BUILD.gn b/components/policy/core/browser/BUILD.gn index 9ace0c2..d638634 100644 --- a/components/policy/core/browser/BUILD.gn +++ b/components/policy/core/browser/BUILD.gn @@ -58,5 +58,15 @@ source_set("browser") { "//components/policy/proto", "//third_party/icu", ] + + if (is_android) { + sources += [ + "android/component_jni_registrar.cc", + "android/component_jni_registrar.h", + "android/policy_converter.cc", + "android/policy_converter.h", + ] + deps += [ "//components/policy/android:jni_headers" ] + } } } diff --git a/components/policy/core/browser/android/DEPS b/components/policy/core/browser/android/DEPS new file mode 100644 index 0000000..c80012b5 --- /dev/null +++ b/components/policy/core/browser/android/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+jni", +] diff --git a/components/policy/core/browser/android/component_jni_registrar.cc b/components/policy/core/browser/android/component_jni_registrar.cc new file mode 100644 index 0000000..985bcce --- /dev/null +++ b/components/policy/core/browser/android/component_jni_registrar.cc @@ -0,0 +1,25 @@ +// Copyright 2015 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 "components/policy/core/browser/android/component_jni_registrar.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_registrar.h" +#include "base/basictypes.h" +#include "components/policy/core/browser/android/policy_converter.h" + +namespace policy { +namespace android { + +static base::android::RegistrationMethod kPolicyRegisteredMethods[] = { + {"PolicyConverter", PolicyConverter::Register}, +}; + +bool RegisterPolicy(JNIEnv* env) { + return base::android::RegisterNativeMethods( + env, kPolicyRegisteredMethods, arraysize(kPolicyRegisteredMethods)); +} + +} // namespace android +} // namespace policy diff --git a/components/policy/core/browser/android/component_jni_registrar.h b/components/policy/core/browser/android/component_jni_registrar.h new file mode 100644 index 0000000..0e35d3d --- /dev/null +++ b/components/policy/core/browser/android/component_jni_registrar.h @@ -0,0 +1,21 @@ +// Copyright 2015 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 COMPONENTS_POLICY_CORE_BROWSER_ANDROID_COMPONENT_JNI_REGISTRAR_H_ +#define COMPONENTS_POLICY_CORE_BROWSER_ANDROID_COMPONENT_JNI_REGISTRAR_H_ + +#include <jni.h> + +#include "components/policy/policy_export.h" + +namespace policy { +namespace android { + +// Register all JNI bindings necessary for the policy component. +bool POLICY_EXPORT RegisterPolicy(JNIEnv* env); + +} // namespace android +} // namespace policy + +#endif // COMPONENTS_POLICY_CORE_BROWSER_ANDROID_COMPONENT_JNI_REGISTRAR_H_ diff --git a/components/policy/core/browser/android/policy_converter.cc b/components/policy/core/browser/android/policy_converter.cc new file mode 100644 index 0000000..85909f3 --- /dev/null +++ b/components/policy/core/browser/android/policy_converter.cc @@ -0,0 +1,197 @@ +// Copyright 2015 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 "components/policy/core/browser/android/policy_converter.h" + +#include <vector> + +#include "base/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "base/json/json_reader.h" +#include "base/logging.h" +#include "base/strings/string16.h" +#include "base/strings/string_number_conversions.h" +#include "base/values.h" +#include "components/policy/core/common/policy_bundle.h" +#include "components/policy/core/common/policy_map.h" +#include "components/policy/core/common/policy_namespace.h" +#include "components/policy/core/common/policy_types.h" +#include "components/policy/core/common/schema.h" +#include "jni/PolicyConverter_jni.h" + +using base::android::ConvertJavaStringToUTF8; + +namespace policy { +namespace android { + +PolicyConverter::PolicyConverter(const Schema* policy_schema) + : policy_schema_(policy_schema), policy_bundle_(new PolicyBundle) { + JNIEnv* env = base::android::AttachCurrentThread(); + java_obj_.Reset(env, Java_PolicyConverter_create( + env, reinterpret_cast<long>(this)).obj()); + DCHECK(!java_obj_.is_null()); +} + +PolicyConverter::~PolicyConverter() { + Java_PolicyConverter_onNativeDestroyed(base::android::AttachCurrentThread(), + java_obj_.obj()); +} + +scoped_ptr<PolicyBundle> PolicyConverter::GetPolicyBundle() { + scoped_ptr<PolicyBundle> filled_bundle(policy_bundle_.Pass()); + policy_bundle_.reset(new PolicyBundle); + return filled_bundle.Pass(); +} + +base::android::ScopedJavaLocalRef<jobject> PolicyConverter::GetJavaObject() { + return base::android::ScopedJavaLocalRef<jobject>(java_obj_); +} + +void PolicyConverter::SetPolicyBoolean(JNIEnv* env, + jobject obj, + jstring policyKey, + jboolean value) { + SetPolicyValue( + ConvertJavaStringToUTF8(env, policyKey), + make_scoped_ptr(new base::FundamentalValue(static_cast<bool>(value)))); +} + +void PolicyConverter::SetPolicyInteger(JNIEnv* env, + jobject obj, + jstring policyKey, + jint value) { + SetPolicyValue( + ConvertJavaStringToUTF8(env, policyKey), + make_scoped_ptr(new base::FundamentalValue(static_cast<int>(value)))); +} + +void PolicyConverter::SetPolicyString(JNIEnv* env, + jobject obj, + jstring policyKey, + jstring value) { + SetPolicyValue(ConvertJavaStringToUTF8(env, policyKey), + make_scoped_ptr(new base::StringValue( + ConvertJavaStringToUTF8(env, value)))); +} + +void PolicyConverter::SetPolicyStringArray(JNIEnv* env, + jobject obj, + jstring policyKey, + jobjectArray array) { + SetPolicyValue(ConvertJavaStringToUTF8(env, policyKey), + ConvertJavaStringArrayToListValue(env, array).Pass()); +} + +// static +scoped_ptr<base::ListValue> PolicyConverter::ConvertJavaStringArrayToListValue( + JNIEnv* env, + jobjectArray array) { + DCHECK(array); + int length = static_cast<int>(env->GetArrayLength(array)); + DCHECK_GE(length, 0) << "Invalid array length: " << length; + + scoped_ptr<base::ListValue> list_value(new base::ListValue()); + for (int i = 0; i < length; ++i) { + jstring str = static_cast<jstring>(env->GetObjectArrayElement(array, i)); + list_value->AppendString(ConvertJavaStringToUTF8(env, str)); + } + + return list_value.Pass(); +} + +// static +scoped_ptr<base::Value> PolicyConverter::ConvertValueToSchema( + scoped_ptr<base::Value> value, + const Schema& schema) { + if (!schema.valid()) + return value.Pass(); + + switch (schema.type()) { + case base::Value::TYPE_NULL: + return base::Value::CreateNullValue(); + + case base::Value::TYPE_BOOLEAN: { + std::string string_value; + if (value->GetAsString(&string_value)) { + if (string_value.compare("true") == 0) + return make_scoped_ptr(new base::FundamentalValue(true)); + + if (string_value.compare("false") == 0) + return make_scoped_ptr(new base::FundamentalValue(false)); + + return value.Pass(); + } + int int_value = 0; + if (value->GetAsInteger(&int_value)) + return make_scoped_ptr(new base::FundamentalValue(int_value != 0)); + + return value.Pass(); + } + + case base::Value::TYPE_INTEGER: { + std::string string_value; + if (value->GetAsString(&string_value)) { + int int_value = 0; + if (base::StringToInt(string_value, &int_value)) + return make_scoped_ptr(new base::FundamentalValue(int_value)); + } + return value.Pass(); + } + + case base::Value::TYPE_DOUBLE: { + std::string string_value; + if (value->GetAsString(&string_value)) { + double double_value = 0; + if (base::StringToDouble(string_value, &double_value)) + return make_scoped_ptr(new base::FundamentalValue(double_value)); + } + return value.Pass(); + } + + // String can't be converted from other types. + case base::Value::TYPE_STRING: { + return value.Pass(); + } + + // Binary is not a valid schema type. + case base::Value::TYPE_BINARY: { + NOTREACHED(); + return scoped_ptr<base::Value>(); + } + + // Complex types have to be deserialized from JSON. + case base::Value::TYPE_DICTIONARY: + case base::Value::TYPE_LIST: { + std::string string_value; + if (value->GetAsString(&string_value)) { + scoped_ptr<base::Value> decoded_value = + base::JSONReader::Read(string_value); + if (decoded_value) + return decoded_value.Pass(); + } + return value.Pass(); + } + } + + NOTREACHED(); + return scoped_ptr<base::Value>(); +} + +// static +bool PolicyConverter::Register(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +void PolicyConverter::SetPolicyValue(const std::string& key, + scoped_ptr<base::Value> value) { + const Schema schema = policy_schema_->GetKnownProperty(key); + const PolicyNamespace ns(POLICY_DOMAIN_CHROME, std::string()); + policy_bundle_->Get(ns) + .Set(key, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + ConvertValueToSchema(value.Pass(), schema).release(), nullptr); +} + +} // namespace android +} // namespace policy diff --git a/components/policy/core/browser/android/policy_converter.h b/components/policy/core/browser/android/policy_converter.h new file mode 100644 index 0000000..a8d2d70 --- /dev/null +++ b/components/policy/core/browser/android/policy_converter.h @@ -0,0 +1,96 @@ +// Copyright 2015 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 COMPONENTS_POLICY_CORE_BROWSER_ANDROID_POLICY_CONVERTER_H +#define COMPONENTS_POLICY_CORE_BROWSER_ANDROID_POLICY_CONVERTER_H + +#include <jni.h> +#include <string> + +#include "base/android/scoped_java_ref.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "components/policy/policy_export.h" + +namespace base { + +class Value; +class ListValue; + +} // namespace base + +namespace policy { + +class PolicyBundle; +class Schema; + +namespace android { + +// Populates natives policies from Java key/value pairs. With its associated +// java classes, allows transforming Android |Bundle|s into |PolicyBundle|s. +class POLICY_EXPORT PolicyConverter { + public: + explicit PolicyConverter(const Schema* policy_schema); + ~PolicyConverter(); + + // Returns a policy bundle containing all policies collected since the last + // call to this method. + scoped_ptr<PolicyBundle> GetPolicyBundle(); + + base::android::ScopedJavaLocalRef<jobject> GetJavaObject(); + + // To be called from Java: + void SetPolicyBoolean(JNIEnv* env, + jobject obj, + jstring policyKey, + jboolean value); + void SetPolicyInteger(JNIEnv* env, + jobject obj, + jstring policyKey, + jint value); + void SetPolicyString(JNIEnv* env, + jobject obj, + jstring policyKey, + jstring value); + void SetPolicyStringArray(JNIEnv* env, + jobject obj, + jstring policyKey, + jobjectArray value); + + // Converts the passed in value to the type desired by the schema. If the + // value is not convertible, it is returned unchanged, so the policy system + // can report the error. + // Note that this method will only look at the type of the schema, not at any + // additional restrictions, or the schema for value's items or properties in + // the case of a list or dictionary value. + // Public for testing. + static scoped_ptr<base::Value> ConvertValueToSchema( + scoped_ptr<base::Value> value, + const Schema& schema); + + // Public for testing. + static scoped_ptr<base::ListValue> ConvertJavaStringArrayToListValue( + JNIEnv* env, + jobjectArray array); + + // Register native methods + static bool Register(JNIEnv* env); + + private: + const Schema* const policy_schema_; + + scoped_ptr<PolicyBundle> policy_bundle_; + + base::android::ScopedJavaGlobalRef<jobject> java_obj_; + + void SetPolicyValue(const std::string& key, + scoped_ptr<base::Value> raw_value); + + DISALLOW_COPY_AND_ASSIGN(PolicyConverter); +}; + +} // namespace android +} // namespace policy + +#endif // COMPONENTS_POLICY_CORE_BROWSER_ANDROID_POLICY_CONVERTER_H diff --git a/chrome/browser/android/policy/policy_manager_unittest.cc b/components/policy/core/browser/android/policy_converter_unittest.cc index 99967b5..748eb5f 100644 --- a/chrome/browser/android/policy/policy_manager_unittest.cc +++ b/components/policy/core/browser/android/policy_converter_unittest.cc @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" #include "base/json/json_writer.h" #include "base/values.h" -#include "chrome/browser/android/policy/policy_manager.h" +#include "components/policy/core/browser/android/policy_converter.h" #include "components/policy/core/common/schema.h" #include "testing/gtest/include/gtest/gtest.h" @@ -14,7 +17,10 @@ using base::ListValue; using base::StringValue; using base::Value; -class PolicyManagerTest : public testing::Test { +namespace policy { +namespace android { + +class PolicyConverterTest : public testing::Test { public: void SetUp() override { const char kSchemaTemplate[] = @@ -35,16 +41,16 @@ class PolicyManagerTest : public testing::Test { "}"; std::string error; - schema_ = policy::Schema::Parse(kSchemaTemplate, &error); + schema_ = Schema::Parse(kSchemaTemplate, &error); ASSERT_TRUE(schema_.valid()) << error; } protected: // Converts the passed in value to the passed in schema, and serializes the // result to JSON, to make it easier to compare with EXPECT_EQ. - std::string Convert(Value* value, const policy::Schema& value_schema) { - scoped_ptr<Value> converted_value( - PolicyManager::ConvertValueToSchema(value, value_schema)); + std::string Convert(Value* value, const Schema& value_schema) { + scoped_ptr<Value> converted_value(PolicyConverter::ConvertValueToSchema( + scoped_ptr<Value>(value), value_schema)); std::string json_string; EXPECT_TRUE( @@ -52,18 +58,46 @@ class PolicyManagerTest : public testing::Test { return json_string; } - policy::Schema schema_; + // Uses|PolicyConverter::ConvertJavaStringArrayToListValue| to convert the + // passed in java array and serializes the result to JSON, to make it easier + // to compare with EXPECT_EQ. + std::string ConvertJavaStringArrayToListValue(JNIEnv* env, + jobjectArray java_array) { + scoped_ptr<ListValue> list = + PolicyConverter::ConvertJavaStringArrayToListValue(env, java_array); + + std::string json_string; + EXPECT_TRUE(base::JSONWriter::Write(*list, &json_string)); + + return json_string; + } + + // Converts the passed in values to a java string array + jobjectArray MakeJavaStringArray(JNIEnv* env, + std::vector<std::string> values) { + jobjectArray java_array = (jobjectArray)env->NewObjectArray( + values.size(), env->FindClass("java/lang/String"), nullptr); + for (size_t i = 0; i < values.size(); i++) { + env->SetObjectArrayElement( + java_array, i, + base::android::ConvertUTF8ToJavaString(env, values[i]).obj()); + } + + return java_array; + } + + Schema schema_; }; -TEST_F(PolicyManagerTest, ConvertToNullValue) { - policy::Schema null_schema = schema_.GetKnownProperty("null"); +TEST_F(PolicyConverterTest, ConvertToNullValue) { + Schema null_schema = schema_.GetKnownProperty("null"); ASSERT_TRUE(null_schema.valid()); EXPECT_EQ("null", Convert(new StringValue("foo"), null_schema)); } -TEST_F(PolicyManagerTest, ConvertToBoolValue) { - policy::Schema bool_schema = schema_.GetKnownProperty("bool"); +TEST_F(PolicyConverterTest, ConvertToBoolValue) { + Schema bool_schema = schema_.GetKnownProperty("bool"); ASSERT_TRUE(bool_schema.valid()); EXPECT_EQ("true", Convert(new FundamentalValue(true), bool_schema)); @@ -79,8 +113,8 @@ TEST_F(PolicyManagerTest, ConvertToBoolValue) { EXPECT_EQ("{}", Convert(new DictionaryValue(), bool_schema)); } -TEST_F(PolicyManagerTest, ConvertToIntValue) { - policy::Schema int_schema = schema_.GetKnownProperty("int"); +TEST_F(PolicyConverterTest, ConvertToIntValue) { + Schema int_schema = schema_.GetKnownProperty("int"); ASSERT_TRUE(int_schema.valid()); EXPECT_EQ("23", Convert(new FundamentalValue(23), int_schema)); @@ -90,8 +124,8 @@ TEST_F(PolicyManagerTest, ConvertToIntValue) { EXPECT_EQ("false", Convert(new FundamentalValue(false), int_schema)); } -TEST_F(PolicyManagerTest, ConvertToDoubleValue) { - policy::Schema double_schema = schema_.GetKnownProperty("double"); +TEST_F(PolicyConverterTest, ConvertToDoubleValue) { + Schema double_schema = schema_.GetKnownProperty("double"); ASSERT_TRUE(double_schema.valid()); EXPECT_EQ("3", Convert(new FundamentalValue(3), double_schema)); @@ -101,16 +135,16 @@ TEST_F(PolicyManagerTest, ConvertToDoubleValue) { EXPECT_EQ("true", Convert(new FundamentalValue(true), double_schema)); } -TEST_F(PolicyManagerTest, ConvertToStringValue) { - policy::Schema string_schema = schema_.GetKnownProperty("string"); +TEST_F(PolicyConverterTest, ConvertToStringValue) { + Schema string_schema = schema_.GetKnownProperty("string"); ASSERT_TRUE(string_schema.valid()); EXPECT_EQ("\"troz\"", Convert(new StringValue("troz"), string_schema)); EXPECT_EQ("4711", Convert(new FundamentalValue(4711), string_schema)); } -TEST_F(PolicyManagerTest, ConvertToListValue) { - policy::Schema list_schema = schema_.GetKnownProperty("list"); +TEST_F(PolicyConverterTest, ConvertToListValue) { + Schema list_schema = schema_.GetKnownProperty("list"); ASSERT_TRUE(list_schema.valid()); ListValue* list = new ListValue; @@ -123,8 +157,17 @@ TEST_F(PolicyManagerTest, ConvertToListValue) { EXPECT_EQ("19", Convert(new FundamentalValue(19), list_schema)); } -TEST_F(PolicyManagerTest, ConvertToDictionaryValue) { - policy::Schema dict_schema = schema_.GetKnownProperty("dict"); +TEST_F(PolicyConverterTest, ConvertFromJavaListToListValue) { + JNIEnv* env = base::android::AttachCurrentThread(); + EXPECT_EQ("[\"foo\",\"bar\",\"baz\"]", + ConvertJavaStringArrayToListValue( + env, MakeJavaStringArray(env, {"foo", "bar", "baz"}))); + EXPECT_EQ("[]", ConvertJavaStringArrayToListValue( + env, MakeJavaStringArray(env, {}))); +} + +TEST_F(PolicyConverterTest, ConvertToDictionaryValue) { + Schema dict_schema = schema_.GetKnownProperty("dict"); ASSERT_TRUE(dict_schema.valid()); DictionaryValue* dict = new DictionaryValue; @@ -135,3 +178,6 @@ TEST_F(PolicyManagerTest, ConvertToDictionaryValue) { EXPECT_EQ("\"fnord\"", Convert(new StringValue("fnord"), dict_schema)); EXPECT_EQ("1729", Convert(new FundamentalValue(1729), dict_schema)); } + +} // namespace android +} // namespace policy diff --git a/components/policy/policy_browser.gypi b/components/policy/policy_browser.gypi index 701a55f..e5a3931 100644 --- a/components/policy/policy_browser.gypi +++ b/components/policy/policy_browser.gypi @@ -61,6 +61,17 @@ 'core/browser/url_blacklist_policy_handler.cc', 'core/browser/url_blacklist_policy_handler.h', ], + 'conditions': [ + ['OS=="android"', { + 'sources': [ + 'core/browser/android/component_jni_registrar.cc', + 'core/browser/android/component_jni_registrar.h', + 'core/browser/android/policy_converter.cc', + 'core/browser/android/policy_converter.h', + ], + 'dependencies': [ 'policy_jni_headers' ] + }] + ] }], ], } |