Revert Revert "Expose chrome policies using Android's App Restrictions Schema"
Android generates alternate resources when dependent on a higher sdk version then the minsdkversion.
This is conflicts with Playstore rules that only permit one resource for App Restrictions.
I have now qualified the resource to apply only for sdk > 21 where the App Restriction API was exposed.
BUG=448829
BUG=446795
TBR=bartfab@chromium.org
Review URL: https://codereview.chromium.org/838263005
Cr-Commit-Position: refs/heads/master@{#311778}
(cherry picked from commit f946bbe6862f98c056288ec1242ed6aab9a7d717)
Review URL: https://codereview.chromium.org/935693002
Cr-Commit-Position: refs/branch-heads/2272@{#313}
Cr-Branched-From: 827a380cfdb31aa54c8d56e63ce2c3fd8c3ba4d4-refs/heads/master@{#310958}
diff --git a/components/policy.gypi b/components/policy.gypi
index ebfbcdd5..7e0533a4 100644
--- a/components/policy.gypi
+++ b/components/policy.gypi
@@ -12,6 +12,7 @@
'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/chrome',
'policy_out_dir': '<(SHARED_INTERMEDIATE_DIR)/policy',
'protoc_out_dir': '<(SHARED_INTERMEDIATE_DIR)/protoc_out',
+ 'android_resources_out_dir': '<(policy_out_dir)/android_resources',
'generate_policy_source_script_path':
'policy/tools/generate_policy_source.py',
'policy_constant_header_path':
@@ -20,6 +21,10 @@
'<(policy_out_dir)/policy/policy_constants.cc',
'protobuf_decoder_path':
'<(policy_out_dir)/policy/cloud_policy_generated.cc',
+ 'app_restrictions_path':
+ '<(android_resources_out_dir)/xml-v21/app_restrictions.xml',
+ 'app_resources_path':
+ '<(android_resources_out_dir)/values-v21/restriction_values.xml',
# This is the "full" protobuf, which defines one protobuf message per
# policy. It is also the format currently used by the server.
'chrome_settings_proto_path':
@@ -109,6 +114,8 @@
'<(protobuf_decoder_path)',
'<(chrome_settings_proto_path)',
'<(cloud_policy_proto_path)',
+ '<(app_restrictions_path)',
+ '<(app_resources_path)',
],
'action_name': 'generate_policy_source',
'action': [
@@ -119,11 +126,21 @@
'--chrome-settings-protobuf=<(chrome_settings_proto_path)',
'--cloud-policy-protobuf=<(cloud_policy_proto_path)',
'--cloud-policy-decoder=<(protobuf_decoder_path)',
+ '--app-restrictions-definition=<(app_restrictions_path)',
+ '--app-restrictions-resources=<(app_resources_path)',
'<(OS)',
'<(chromeos)',
'policy/resources/policy_templates.json',
],
'message': 'Generating policy source',
+ 'conditions': [
+ ['OS!="android"', {
+ 'outputs!': [
+ '<(app_restrictions_path)',
+ '<(app_resources_path)',
+ ],
+ }],
+ ],
},
],
'direct_dependent_settings': {
diff --git a/components/policy/BUILD.gn b/components/policy/BUILD.gn
index 5e405f7..d8d7c92 100644
--- a/components/policy/BUILD.gn
+++ b/components/policy/BUILD.gn
@@ -47,6 +47,9 @@
# build puts everything into the following directory. We do the same for now.
policy_gen_dir = "$root_gen_dir/policy"
+ # Directory for generating Android App Restrictions resources
+ android_resources_gen_dir = "$policy_gen_dir/android_resources"
+
# This protobuf is equivalent to chrome_settings.proto but shares messages
# for policies of the same type, so that less classes have to be generated
# and compiled.
@@ -59,6 +62,10 @@
constants_header_path = "$policy_gen_dir/policy_constants.h"
constants_source_path = "$policy_gen_dir/policy_constants.cc"
protobuf_decoder_path = "$policy_gen_dir/cloud_policy_generated.cc"
+ app_restrictions_path =
+ "$android_resources_gen_dir/xml-v21/app_restrictions.xml"
+ app_resources_path =
+ "$android_resources_gen_dir/values-v21/restriction_values.xml"
action("cloud_policy_code_generate") {
script = "tools/generate_policy_source.py"
@@ -78,8 +85,17 @@
protobuf_decoder_path,
chrome_settings_proto_path,
cloud_policy_proto_path,
+ app_restrictions_path,
+ app_resources_path,
]
+ if (os != "android") {
+ outputs -= [
+ app_restrictions_path,
+ app_resources_path,
+ ]
+ }
+
args = [
"--policy-constants-header=" +
rebase_path(constants_header_path, root_build_dir),
@@ -91,6 +107,10 @@
rebase_path(cloud_policy_proto_path, root_build_dir),
"--cloud-policy-decoder=" +
rebase_path(protobuf_decoder_path, root_build_dir),
+ "--app-restrictions-definition=" +
+ rebase_path(app_restrictions_path, root_build_dir),
+ "--app-restrictions-resources=" +
+ rebase_path(app_resources_path, root_build_dir),
os,
chromeos_flag,
rebase_path("resources/policy_templates.json", root_build_dir),
diff --git a/components/policy/tools/generate_policy_source.py b/components/policy/tools/generate_policy_source.py
index c3096c7..e343e33 100755
--- a/components/policy/tools/generate_policy_source.py
+++ b/components/policy/tools/generate_policy_source.py
@@ -18,6 +18,7 @@
import sys
import textwrap
import types
+from xml.sax.saxutils import escape as xml_escape
CHROME_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome'
@@ -27,23 +28,34 @@
class PolicyDetails:
"""Parses a policy template and caches all its details."""
- # Maps policy types to a tuple with 3 other types:
+ # Maps policy types to a tuple with 5 other types:
# - the equivalent base::Value::Type or 'TYPE_EXTERNAL' if the policy
# references external data
# - the equivalent Protobuf field type
# - the name of one of the protobufs for shared policy types
+ # - the equivalent type in Android's App Restriction Schema
+ # - whether the equivalent app restriction type needs supporting resources
# TODO(joaodasilva): refactor the 'dict' type into a more generic 'json' type
# that can also be used to represent lists of other JSON objects.
TYPE_MAP = {
- 'dict': ('TYPE_DICTIONARY', 'string', 'String'),
- 'external': ('TYPE_EXTERNAL', 'string', 'String'),
- 'int': ('TYPE_INTEGER', 'int64', 'Integer'),
- 'int-enum': ('TYPE_INTEGER', 'int64', 'Integer'),
- 'list': ('TYPE_LIST', 'StringList', 'StringList'),
- 'main': ('TYPE_BOOLEAN', 'bool', 'Boolean'),
- 'string': ('TYPE_STRING', 'string', 'String'),
- 'string-enum': ('TYPE_STRING', 'string', 'String'),
- 'string-enum-list': ('TYPE_LIST', 'StringList', 'StringList'),
+ 'dict': ('TYPE_DICTIONARY', 'string', 'String',
+ 'string', False),
+ 'external': ('TYPE_EXTERNAL', 'string', 'String',
+ 'invalid', False),
+ 'int': ('TYPE_INTEGER', 'int64', 'Integer',
+ 'integer', False),
+ 'int-enum': ('TYPE_INTEGER', 'int64', 'Integer',
+ 'choice', True),
+ 'list': ('TYPE_LIST', 'StringList', 'StringList',
+ 'string', False),
+ 'main': ('TYPE_BOOLEAN', 'bool', 'Boolean',
+ 'bool', False),
+ 'string': ('TYPE_STRING', 'string', 'String',
+ 'string', False),
+ 'string-enum': ('TYPE_STRING', 'string', 'String',
+ 'choice', True),
+ 'string-enum-list': ('TYPE_LIST', 'StringList', 'StringList',
+ 'multi-select', True),
}
class EnumItem:
@@ -85,8 +97,9 @@
if not PolicyDetails.TYPE_MAP.has_key(policy['type']):
raise NotImplementedError('Unknown policy type for %s: %s' %
(policy['name'], policy['type']))
- self.policy_type, self.protobuf_type, self.policy_protobuf_type = \
- PolicyDetails.TYPE_MAP[policy['type']]
+ self.policy_type, self.protobuf_type, self.policy_protobuf_type, \
+ self.restriction_type, self.has_restriction_resources = \
+ PolicyDetails.TYPE_MAP[policy['type']]
self.schema = policy['schema']
self.desc = '\n'.join(
@@ -136,6 +149,17 @@
dest='cloud_policy_decoder_path',
help='generate C++ code decoding the cloud policy protobuf',
metavar='FILE')
+ parser.add_option('--ard', '--app-restrictions-definition',
+ dest='app_restrictions_path',
+ help='generate an XML file as specified by '
+ 'Android\'s App Restriction Schema',
+ metavar='FILE')
+ parser.add_option('--arr', '--app-restrictions-resources',
+ dest='app_resources_path',
+ help='generate an XML file with resources supporting the '
+ 'restrictions defined in --app-restrictions-definition '
+ 'parameter',
+ metavar='FILE')
(opts, args) = parser.parse_args()
@@ -153,10 +177,10 @@
for policy in _Flatten(template_file_contents) ]
sorted_policy_details = sorted(policy_details, key=lambda policy: policy.name)
- def GenerateFile(path, writer, sorted=False):
+ def GenerateFile(path, writer, sorted=False, xml=False):
if path:
with open(path, 'w') as f:
- _OutputGeneratedWarningHeader(f, template_file_name)
+ _OutputGeneratedWarningHeader(f, template_file_name, xml)
writer(sorted and sorted_policy_details or policy_details, os, f)
GenerateFile(opts.header_path, _WritePolicyConstantHeader, sorted=True)
@@ -165,17 +189,32 @@
GenerateFile(opts.chrome_settings_proto_path, _WriteChromeSettingsProtobuf)
GenerateFile(opts.cloud_policy_decoder_path, _WriteCloudPolicyDecoder)
+ if os == 'android':
+ GenerateFile(opts.app_restrictions_path, _WriteAppRestrictions, xml=True)
+ GenerateFile(opts.app_resources_path, _WriteResourcesForPolicies, xml=True)
+
return 0
#------------------ shared helpers ---------------------------------#
-def _OutputGeneratedWarningHeader(f, template_file_path):
- f.write('//\n'
- '// DO NOT MODIFY THIS FILE DIRECTLY!\n'
- '// IT IS GENERATED BY generate_policy_source.py\n'
- '// FROM ' + template_file_path + '\n'
- '//\n\n')
+def _OutputGeneratedWarningHeader(f, template_file_path, xml_style):
+ left_margin = '//'
+ if xml_style:
+ left_margin = ' '
+ f.write('<?xml version="1.0" encoding="utf-8"?>\n'
+ '<!--\n')
+ else:
+ f.write('//\n')
+
+ f.write(left_margin + ' DO NOT MODIFY THIS FILE DIRECTLY!\n')
+ f.write(left_margin + ' IT IS GENERATED BY generate_policy_source.py\n')
+ f.write(left_margin + ' FROM ' + template_file_path + '\n')
+
+ if xml_style:
+ f.write('-->\n\n')
+ else:
+ f.write(left_margin + '\n\n')
COMMENT_WRAPPER = textwrap.TextWrapper()
@@ -561,7 +600,7 @@
return self.id_map[id_str]
def ResolveID(self, index, params):
- return params[:index] + (self.GetByID(params[index]),) + params[index+1:]
+ return params[:index] + (self.GetByID(params[index]),) + params[index + 1:]
def ResolveReferences(self):
"""Resolve reference mapping, required to be called after Generate()
@@ -968,5 +1007,82 @@
f.write(CPP_FOOT)
+def _EscapeResourceString(raw_resource):
+ if type(raw_resource) == int:
+ return raw_resource
+ return xml_escape(raw_resource)\
+ .replace('\\', '\\\\')\
+ .replace('\"','\\\"')\
+ .replace('\'','\\\'')
+
+def _WriteAppRestrictions(policies, os, f):
+
+ def WriteRestrictionCommon(key):
+ f.write(' <restriction\n'
+ ' android:key="%s"\n' % key)
+ f.write(' android:title="@string/%sTitle"\n' % key)
+ f.write(' android:description="@string/%sDesc"\n' % key)
+
+ def WriteItemsDefinition(key):
+ f.write(' android:entries="@array/%sEntries"\n' % key)
+ f.write(' android:entryValues="@array/%sValues"\n' % key)
+
+ def WriteAppRestriction(policy):
+ policy_name = policy.name
+ WriteRestrictionCommon(policy_name)
+
+ if policy.has_restriction_resources:
+ WriteItemsDefinition(policy_name)
+
+ f.write(' android:restrictionType="%s"/>' % policy.restriction_type)
+ f.write('\n\n')
+
+ # _WriteAppRestrictions body
+ f.write('<restrictions xmlns:android="'
+ 'http://schemas.android.com/apk/res/android">\n\n')
+ for policy in policies:
+ if policy.is_supported and policy.restriction_type != 'invalid':
+ WriteAppRestriction(policy)
+ f.write('</restrictions>')
+
+
+def _WriteResourcesForPolicies(policies, os, f):
+
+ # TODO(knn): Update this to support i18n.
+ def WriteString(key, value):
+ f.write(' <string name="%s">%s</string>\n'
+ % (key, _EscapeResourceString(value)))
+
+ def WriteItems(key, items):
+ if items:
+ f.write(' <string-array name="%sEntries">\n' % key)
+ for item in items:
+ f.write(' <item>%s</item>\n' %
+ _EscapeResourceString(item.caption))
+ f.write(' </string-array>\n')
+ f.write(' <string-array name="%sValues">\n' % key)
+ for item in items:
+ f.write(' <item>%s</item>\n' % _EscapeResourceString(item.value))
+ f.write(' </string-array>\n')
+
+ def WriteResourceForPolicy(policy):
+ policy_name = policy.name
+ WriteString(policy_name + 'Title', policy.caption)
+
+ # Get the first line of the policy description.
+ description = policy.desc.split('\n', 1)[0]
+ WriteString(policy_name + 'Desc', description)
+
+ if policy.has_restriction_resources:
+ WriteItems(policy_name, policy.items)
+
+ # _WriteResourcesForPolicies body
+ f.write('<resources>\n\n')
+ for policy in policies:
+ if policy.is_supported and policy.restriction_type != 'invalid':
+ WriteResourceForPolicy(policy)
+ f.write('</resources>')
+
+
if __name__ == '__main__':
sys.exit(main())