Revert "Revert "Merge changes from topic 'fsconfig-2'"" am: 2d7c86dfea am: feb4f2e54a

am: 8a2ed5159c

Change-Id: I7ff77ba1282fbddedbd10a3a63b055ac36ee83ae
This commit is contained in:
Elliott Hughes 2016-12-27 21:15:54 +00:00 committed by android-build-merger
commit 3315b71ca8
7 changed files with 1668 additions and 223 deletions

View file

@ -89,6 +89,14 @@ PRODUCT_PACKAGES += \
sepolicy \
service_contexts
# AID Generation for
# <pwd.h> and <grp.h>
PRODUCT_PACKAGES += \
passwd \
group \
fs_config_files \
fs_config_dirs
# Ensure that this property is always defined so that bionic_systrace.cpp
# can rely on it being initially set by init.
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += \

View file

@ -81,19 +81,35 @@ LOCAL_SHARED_LIBRARIES := libcutils
LOCAL_CFLAGS := -Werror -Wno-error=\#warnings
ifneq ($(TARGET_FS_CONFIG_GEN),)
system_android_filesystem_config := system/core/include/private/android_filesystem_config.h
# Generate the "generated_oem_aid.h" file
oem := $(local-generated-sources-dir)/generated_oem_aid.h
$(oem): PRIVATE_LOCAL_PATH := $(LOCAL_PATH)
$(oem): PRIVATE_TARGET_FS_CONFIG_GEN := $(TARGET_FS_CONFIG_GEN)
$(oem): PRIVATE_ANDROID_FS_HDR := $(system_android_filesystem_config)
$(oem): PRIVATE_CUSTOM_TOOL = $(PRIVATE_LOCAL_PATH)/fs_config_generator.py oemaid --aid-header=$(PRIVATE_ANDROID_FS_HDR) $(PRIVATE_TARGET_FS_CONFIG_GEN) > $@
$(oem): $(TARGET_FS_CONFIG_GEN) $(LOCAL_PATH)/fs_config_generator.py
$(transform-generated-source)
# Generate the fs_config header
gen := $(local-generated-sources-dir)/$(ANDROID_FS_CONFIG_H)
$(gen): PRIVATE_LOCAL_PATH := $(LOCAL_PATH)
$(gen): PRIVATE_TARGET_FS_CONFIG_GEN := $(TARGET_FS_CONFIG_GEN)
$(gen): PRIVATE_CUSTOM_TOOL = $(PRIVATE_LOCAL_PATH)/fs_config_generator.py $(PRIVATE_TARGET_FS_CONFIG_GEN) > $@
$(gen): $(TARGET_FS_CONFIG_GEN) $(LOCAL_PATH)/fs_config_generator.py
$(gen): PRIVATE_ANDROID_FS_HDR := $(system_android_filesystem_config)
$(gen): PRIVATE_CUSTOM_TOOL = $(PRIVATE_LOCAL_PATH)/fs_config_generator.py fsconfig --aid-header=$(PRIVATE_ANDROID_FS_HDR) $(PRIVATE_TARGET_FS_CONFIG_GEN) > $@
$(gen): $(TARGET_FS_CONFIG_GEN) $(system_android_filesystem_config) $(LOCAL_PATH)/fs_config_generator.py
$(transform-generated-source)
LOCAL_GENERATED_SOURCES := $(gen)
LOCAL_GENERATED_SOURCES := $(oem) $(gen)
my_fs_config_h := $(gen)
my_gen_oem_aid := $(oem)
gen :=
oem :=
endif
LOCAL_C_INCLUDES := $(dir $(my_fs_config_h))
LOCAL_C_INCLUDES := $(dir $(my_fs_config_h)) $(dir $(my_gen_oem_aid))
include $(BUILD_HOST_EXECUTABLE)
fs_config_generate_bin := $(LOCAL_INSTALLED_MODULE)
@ -122,6 +138,60 @@ $(LOCAL_BUILT_MODULE): $(fs_config_generate_bin)
@mkdir -p $(dir $@)
$< -F -o $@
# The newer passwd/group targets are only generated if you
# use the new TARGET_FS_CONFIG_GEN method.
ifneq ($(TARGET_FS_CONFIG_GEN),)
##################################
# Build the oemaid library when fs config files are present.
# Intentionally break build if you require generated AIDS
# header file, but are not using any fs config files.
include $(CLEAR_VARS)
LOCAL_MODULE := liboemaids
LOCAL_EXPORT_C_INCLUDE_DIRS := $(dir $(my_gen_oem_aid))
LOCAL_EXPORT_C_INCLUDE_DEPS := $(my_gen_oem_aid)
include $(BUILD_STATIC_LIBRARY)
##################################
# Generate the system/etc/passwd text file for the target
# This file may be empty if no AIDs are defined in
# TARGET_FS_CONFIG_GEN files.
include $(CLEAR_VARS)
LOCAL_MODULE := passwd
LOCAL_MODULE_CLASS := ETC
include $(BUILD_SYSTEM)/base_rules.mk
$(LOCAL_BUILT_MODULE): PRIVATE_LOCAL_PATH := $(LOCAL_PATH)
$(LOCAL_BUILT_MODULE): PRIVATE_TARGET_FS_CONFIG_GEN := $(TARGET_FS_CONFIG_GEN)
$(LOCAL_BUILT_MODULE): PRIVATE_ANDROID_FS_HDR := $(system_android_filesystem_config)
$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/fs_config_generator.py $(TARGET_FS_CONFIG_GEN) $(system_android_filesystem_config)
@mkdir -p $(dir $@)
$(hide) $< passwd --aid-header=$(PRIVATE_ANDROID_FS_HDR) $(PRIVATE_TARGET_FS_CONFIG_GEN) > $@
##################################
# Generate the system/etc/group text file for the target
# This file may be empty if no AIDs are defined in
# TARGET_FS_CONFIG_GEN files.
include $(CLEAR_VARS)
LOCAL_MODULE := group
LOCAL_MODULE_CLASS := ETC
include $(BUILD_SYSTEM)/base_rules.mk
$(LOCAL_BUILT_MODULE): PRIVATE_LOCAL_PATH := $(LOCAL_PATH)
$(LOCAL_BUILT_MODULE): PRIVATE_TARGET_FS_CONFIG_GEN := $(TARGET_FS_CONFIG_GEN)
$(LOCAL_BUILT_MODULE): PRIVATE_ANDROID_FS_HDR := $(system_android_filesystem_config)
$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/fs_config_generator.py $(TARGET_FS_CONFIG_GEN) $(system_android_filesystem_config)
@mkdir -p $(dir $@)
$(hide) $< group --aid-header=$(PRIVATE_ANDROID_FS_HDR) $(PRIVATE_TARGET_FS_CONFIG_GEN) > $@
system_android_filesystem_config :=
endif
ANDROID_FS_CONFIG_H :=
my_fs_config_h :=
fs_config_generate_bin :=
my_gen_oem_aid :=

View file

@ -50,12 +50,12 @@ mode:
prefixed with a 0, else mode is used as is.
user:
The exact, C define for a valid AID. Note custom AIDs can be defined in the
Either the C define for a valid AID or the friendly name. For instance both
AID_RADIO and radio are acceptable. Note custom AIDs can be defined in the
AID section documented below.
group:
The exact, C define for a valid AID. Note custom AIDs can be defined in the
AID section documented below.
Same as user.
caps:
The name as declared in
@ -82,7 +82,8 @@ value: <number>
Where:
[AID_<name>]
The <name> can be any valid character for a #define identifier in C.
The <name> can contain characters in the set uppercase, numbers
and underscores.
value:
A valid C style number string. Hex, octal, binary and decimal are supported.
@ -118,3 +119,24 @@ The declared AIDS are sorted in ascending numerical order based on the option "v
representation of value is preserved. Both choices were made for maximum readability of the generated
file and to line up files. Sync lines are placed with the source file as comments in the generated
header file.
For OEMs wishing to use the define AIDs in their native code, one can access the generated header
file like so:
1. In your C code just #include "generated_oem_aid.h" and start using the declared identifiers.
2. In your Makefile add this static library like so: LOCAL_STATIC_LIBRARIES := liboemaids
Unit Tests:
From within the fs_config directory, unit tests can be executed like so:
$ python -m unittest test_fs_config_generator.Tests
.............
----------------------------------------------------------------------
Ran 13 tests in 0.004s
OK
One could also use nose if they would like:
$ nose2
To add new tests, simply add a test_<xxx> method to the test class. It will automatically
get picked up and added to the test suite.

View file

@ -19,13 +19,6 @@
** by the device side of adb.
*/
/*
** Resorting to the default file means someone requested fs_config_dirs or
** fs_config_files in their device configuration without providing an
** associated header.
*/
#warning No device-supplied android_filesystem_config.h, using empty default.
/* Rules for directories.
** These rules are applied based on "first match", so they
** should start with the most specific path and work their

File diff suppressed because it is too large Load diff

5
tools/fs_config/pylintrc Normal file
View file

@ -0,0 +1,5 @@
[MESSAGES CONTROL]
disable=fixme,design,locally-disabled,too-many-lines
[VARIABLES]
dummy-variables-rgx=_|dummy

View file

@ -0,0 +1,313 @@
#!/usr/bin/env python
"""Unit test suite for the fs_config_genertor.py tool."""
import tempfile
import textwrap
import unittest
from fs_config_generator import AID
from fs_config_generator import AIDHeaderParser
from fs_config_generator import FSConfigFileParser
from fs_config_generator import FSConfig
from fs_config_generator import Utils
# Disable protected access so we can test class internal
# methods. Also, disable invalid-name as some of the
# class method names are over length.
# pylint: disable=protected-access,invalid-name
class Tests(unittest.TestCase):
"""Test class for unit tests"""
def test_is_overlap(self):
"""Test overlap detection helper"""
self.assertTrue(AIDHeaderParser._is_overlap((0, 1), (1, 2)))
self.assertTrue(AIDHeaderParser._is_overlap((0, 100), (90, 200)))
self.assertTrue(AIDHeaderParser._is_overlap((20, 50), (1, 101)))
self.assertFalse(AIDHeaderParser._is_overlap((0, 100), (101, 200)))
self.assertFalse(AIDHeaderParser._is_overlap((-10, 0), (10, 20)))
def test_in_any_range(self):
"""Test if value in range"""
self.assertFalse(Utils.in_any_range(50, [(100, 200), (1, 2), (1, 1)]))
self.assertFalse(Utils.in_any_range(250, [(100, 200), (1, 2), (1, 1)]))
self.assertTrue(Utils.in_any_range(100, [(100, 200), (1, 2), (1, 1)]))
self.assertTrue(Utils.in_any_range(200, [(100, 200), (1, 2), (1, 1)]))
self.assertTrue(Utils.in_any_range(150, [(100, 200)]))
def test_aid(self):
"""Test AID class constructor"""
aid = AID('AID_FOO_BAR', '0xFF', 'myfakefile')
self.assertEquals(aid.identifier, 'AID_FOO_BAR')
self.assertEquals(aid.value, '0xFF')
self.assertEquals(aid.found, 'myfakefile')
self.assertEquals(aid.normalized_value, '255')
self.assertEquals(aid.friendly, 'foo_bar')
aid = AID('AID_MEDIA_EX', '1234', 'myfakefile')
self.assertEquals(aid.identifier, 'AID_MEDIA_EX')
self.assertEquals(aid.value, '1234')
self.assertEquals(aid.found, 'myfakefile')
self.assertEquals(aid.normalized_value, '1234')
self.assertEquals(aid.friendly, 'mediaex')
def test_aid_header_parser_good(self):
"""Test AID Header Parser good input file"""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(
textwrap.dedent("""
#define AID_FOO 1000
#define AID_BAR 1001
#define SOMETHING "something"
#define AID_OEM_RESERVED_START 2900
#define AID_OEM_RESERVED_END 2999
#define AID_OEM_RESERVED_1_START 7000
#define AID_OEM_RESERVED_1_END 8000
"""))
temp_file.flush()
parser = AIDHeaderParser(temp_file.name)
oem_ranges = parser.oem_ranges
aids = parser.aids
self.assertTrue((2900, 2999) in oem_ranges)
self.assertFalse((5000, 6000) in oem_ranges)
for aid in aids:
self.assertTrue(aid.normalized_value in ['1000', '1001'])
self.assertFalse(aid.normalized_value in ['1', '2', '3'])
def test_aid_header_parser_good_unordered(self):
"""Test AID Header Parser good unordered input file"""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(
textwrap.dedent("""
#define AID_FOO 1000
#define AID_OEM_RESERVED_1_END 8000
#define AID_BAR 1001
#define SOMETHING "something"
#define AID_OEM_RESERVED_END 2999
#define AID_OEM_RESERVED_1_START 7000
#define AID_OEM_RESERVED_START 2900
"""))
temp_file.flush()
parser = AIDHeaderParser(temp_file.name)
oem_ranges = parser.oem_ranges
aids = parser.aids
self.assertTrue((2900, 2999) in oem_ranges)
self.assertFalse((5000, 6000) in oem_ranges)
for aid in aids:
self.assertTrue(aid.normalized_value in ['1000', '1001'])
self.assertFalse(aid.normalized_value in ['1', '2', '3'])
def test_aid_header_parser_bad_aid(self):
"""Test AID Header Parser bad aid input file"""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(
textwrap.dedent("""
#define AID_FOO "bad"
"""))
temp_file.flush()
with self.assertRaises(SystemExit):
AIDHeaderParser(temp_file.name)
def test_aid_header_parser_bad_oem_range(self):
"""Test AID Header Parser bad oem range input file"""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(
textwrap.dedent("""
#define AID_OEM_RESERVED_START 2900
#define AID_OEM_RESERVED_END 1800
"""))
temp_file.flush()
with self.assertRaises(SystemExit):
AIDHeaderParser(temp_file.name)
def test_aid_header_parser_bad_oem_range_no_end(self):
"""Test AID Header Parser bad oem range (no end) input file"""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(
textwrap.dedent("""
#define AID_OEM_RESERVED_START 2900
"""))
temp_file.flush()
with self.assertRaises(SystemExit):
AIDHeaderParser(temp_file.name)
def test_aid_header_parser_bad_oem_range_no_start(self):
"""Test AID Header Parser bad oem range (no start) input file"""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(
textwrap.dedent("""
#define AID_OEM_RESERVED_END 2900
"""))
temp_file.flush()
with self.assertRaises(SystemExit):
AIDHeaderParser(temp_file.name)
def test_aid_header_parser_bad_oem_range_mismatch_start_end(self):
"""Test AID Header Parser bad oem range mismatched input file"""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(
textwrap.dedent("""
#define AID_OEM_RESERVED_START 2900
#define AID_OEM_RESERVED_2_END 2900
"""))
temp_file.flush()
with self.assertRaises(SystemExit):
AIDHeaderParser(temp_file.name)
def test_aid_header_parser_bad_duplicate_ranges(self):
"""Test AID Header Parser exits cleanly on duplicate AIDs"""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(
textwrap.dedent("""
#define AID_FOO 100
#define AID_BAR 100
"""))
temp_file.flush()
with self.assertRaises(SystemExit):
AIDHeaderParser(temp_file.name)
def test_aid_header_parser_no_bad_aids(self):
"""Test AID Header Parser that it doesn't contain:
Ranges, ie things the end with "_START" or "_END"
AID_APP
AID_USER
For more details see:
- https://android-review.googlesource.com/#/c/313024
- https://android-review.googlesource.com/#/c/313169
"""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(
textwrap.dedent("""
#define AID_APP 10000 /* TODO: switch users over to AID_APP_START */
#define AID_APP_START 10000 /* first app user */
#define AID_APP_END 19999 /* last app user */
#define AID_CACHE_GID_START 20000 /* start of gids for apps to mark cached data */
#define AID_CACHE_GID_END 29999 /* end of gids for apps to mark cached data */
#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
#define AID_SHARED_GID_END 59999 /* end of gids for apps in each user to share */
#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
#define AID_USER 100000 /* TODO: switch users over to AID_USER_OFFSET */
#define AID_USER_OFFSET 100000 /* offset for uid ranges for each user */
"""))
temp_file.flush()
parser = AIDHeaderParser(temp_file.name)
aids = parser.aids
bad_aids = ['_START', '_END', 'AID_APP', 'AID_USER']
for aid in aids:
self.assertFalse(
any(bad in aid.identifier for bad in bad_aids),
'Not expecting keywords "%s" in aids "%s"' %
(str(bad_aids), str([tmp.identifier for tmp in aids])))
def test_fs_config_file_parser_good(self):
"""Test FSConfig Parser good input file"""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(
textwrap.dedent("""
[/system/bin/file]
user: AID_FOO
group: AID_SYSTEM
mode: 0777
caps: BLOCK_SUSPEND
[/vendor/path/dir/]
user: AID_FOO
group: AID_SYSTEM
mode: 0777
caps: 0
[AID_OEM1]
# 5001 in base16
value: 0x1389
"""))
temp_file.flush()
parser = FSConfigFileParser([temp_file.name], [(5000, 5999)])
files = parser.files
dirs = parser.dirs
aids = parser.aids
self.assertEquals(len(files), 1)
self.assertEquals(len(dirs), 1)
self.assertEquals(len(aids), 1)
aid = aids[0]
fcap = files[0]
dcap = dirs[0]
self.assertEqual(fcap,
FSConfig('0777', 'AID_FOO', 'AID_SYSTEM',
'(1ULL << CAP_BLOCK_SUSPEND)',
'/system/bin/file', temp_file.name))
self.assertEqual(dcap,
FSConfig('0777', 'AID_FOO', 'AID_SYSTEM', '(0)',
'/vendor/path/dir/', temp_file.name))
self.assertEqual(aid, AID('AID_OEM1', '0x1389', temp_file.name))
def test_fs_config_file_parser_bad(self):
"""Test FSConfig Parser bad input file"""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(
textwrap.dedent("""
[/system/bin/file]
caps: BLOCK_SUSPEND
"""))
temp_file.flush()
with self.assertRaises(SystemExit):
FSConfigFileParser([temp_file.name], [(5000, 5999)])
def test_fs_config_file_parser_bad_aid_range(self):
"""Test FSConfig Parser bad aid range value input file"""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(
textwrap.dedent("""
[AID_OEM1]
value: 25
"""))
temp_file.flush()
with self.assertRaises(SystemExit):
FSConfigFileParser([temp_file.name], [(5000, 5999)])