Merge "Revert "Check in P dark greylist, use it for hidden API list generation""

This commit is contained in:
David Brazdil
2018-09-11 15:27:40 +00:00
committed by Gerrit Code Review
4 changed files with 105 additions and 120944 deletions

View File

@@ -336,7 +336,6 @@ $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST): \
frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py \ frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py \
frameworks/base/config/hiddenapi-light-greylist.txt \ frameworks/base/config/hiddenapi-light-greylist.txt \
frameworks/base/config/hiddenapi-vendor-list.txt \ frameworks/base/config/hiddenapi-vendor-list.txt \
frameworks/base/config/hiddenapi-dark-greylist.txt \
frameworks/base/config/hiddenapi-force-blacklist.txt \ frameworks/base/config/hiddenapi-force-blacklist.txt \
$(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \ $(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \
$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \ $(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \
@@ -345,15 +344,12 @@ $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST): \
--input-public $(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \ --input-public $(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \
--input-private $(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \ --input-private $(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \
--input-whitelists $(PRIVATE_WHITELIST_INPUTS) \ --input-whitelists $(PRIVATE_WHITELIST_INPUTS) \
--input-light-greylists \ --input-greylists \
frameworks/base/config/hiddenapi-light-greylist.txt \ frameworks/base/config/hiddenapi-light-greylist.txt \
frameworks/base/config/hiddenapi-vendor-list.txt \ frameworks/base/config/hiddenapi-vendor-list.txt \
<(comm -12 <(sort $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE)) \ <(comm -12 <(sort $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE)) \
$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST)) \ $(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST)) \
$(PRIVATE_GREYLIST_INPUTS) \ $(PRIVATE_GREYLIST_INPUTS) \
--input-dark-greylists \
frameworks/base/config/hiddenapi-dark-greylist.txt \
$(PRIVATE_DARKGREYLIST_INPUTS) \
--input-blacklists frameworks/base/config/hiddenapi-force-blacklist.txt \ --input-blacklists frameworks/base/config/hiddenapi-force-blacklist.txt \
--output-whitelist $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST).tmp \ --output-whitelist $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST).tmp \
--output-light-greylist $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST).tmp \ --output-light-greylist $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST).tmp \

File diff suppressed because it is too large Load Diff

View File

@@ -45,11 +45,8 @@ def get_args():
'--input-whitelists', nargs='*', '--input-whitelists', nargs='*',
help='Lists of members to force on whitelist') help='Lists of members to force on whitelist')
parser.add_argument( parser.add_argument(
'--input-light-greylists', nargs='*', '--input-greylists', nargs='*',
help='Lists of members to force on light greylist') help='Lists of members to force on light greylist')
parser.add_argument(
'--input-dark-greylists', nargs='*',
help='Lists of members to force on dark greylist')
parser.add_argument( parser.add_argument(
'--input-blacklists', nargs='*', '--input-blacklists', nargs='*',
help='Lists of members to force on blacklist') help='Lists of members to force on blacklist')
@@ -83,20 +80,14 @@ def write_lines(filename, lines):
with open(filename, 'w') as f: with open(filename, 'w') as f:
f.writelines(lines) f.writelines(lines)
def move_between_sets(subset, src, dst, source = "<unknown>", ignoreMissing = False): def move_between_sets(subset, src, dst, source = "<unknown>"):
"""Removes a subset of elements from one set and add it to another. """Removes a subset of elements from one set and add it to another.
Args: Args:
subset (set): The subset of `src` to be moved from `src` to `dst`. subset (set): The subset of `src` to be moved from `src` to `dst`.
src (set): Source set. Must be a superset of `subset`. src (set): Source set. Must be a superset of `subset`.
dst (set): Destination set. Must be disjoint with `subset`. dst (set): Destination set. Must be disjoint with `subset`.
source (string): Name of the data source.
ignoreMissing (bool): If true, do not check whether `src` is a superset of `subset`.
""" """
if ignoreMissing:
# Some entries in `subset` may not be in `src`. Remove such entries first.
subset.intersection_update(src)
else:
assert src.issuperset(subset), ( assert src.issuperset(subset), (
"Error processing: {}\n" "Error processing: {}\n"
"The following entries were not found:\n" "The following entries were not found:\n"
@@ -108,6 +99,42 @@ def move_between_sets(subset, src, dst, source = "<unknown>", ignoreMissing = Fa
dst.update(subset) dst.update(subset)
src.difference_update(subset) src.difference_update(subset)
def get_package_name(signature):
"""Returns the package name prefix of a class member signature.
Example: "Ljava/lang/String;->hashCode()J" --> "Ljava/lang/"
Args:
signature (string): Member signature
Returns
string: Package name of the given member
"""
class_name_end = signature.find("->")
assert class_name_end != -1, "Invalid signature: {}".format(signature)
package_name_end = signature.rfind("/", 0, class_name_end)
assert package_name_end != -1, "Invalid signature: {}".format(signature)
return signature[:package_name_end + 1]
def all_package_names(*args):
"""Returns a set of packages names in given lists of member signatures.
Example: args = [ set([ "Lpkg1/ClassA;->foo()V", "Lpkg2/ClassB;->bar()J" ]),
set([ "Lpkg1/ClassC;->baz()Z" ]) ]
return value = set([ "Lpkg1/", "Lpkg2" ])
Args:
*args (list): List of sets to iterate over and extract the package names
of its elements (member signatures)
Returns:
set: All package names extracted from the given lists of signatures.
"""
packages = set()
for arg in args:
packages = packages.union(map(get_package_name, arg))
return packages
def move_all(src, dst): def move_all(src, dst):
"""Moves all elements of one set to another. """Moves all elements of one set to another.
@@ -117,7 +144,7 @@ def move_all(src, dst):
""" """
move_between_sets(src, src, dst) move_between_sets(src, src, dst)
def move_from_files(filenames, src, dst, ignoreMissing = False): def move_from_files(filenames, src, dst):
"""Loads member signatures from a list of files and moves them to a given set. """Loads member signatures from a list of files and moves them to a given set.
Opens files in `filenames`, reads all their lines and moves those from `src` Opens files in `filenames`, reads all their lines and moves those from `src`
@@ -130,7 +157,7 @@ def move_from_files(filenames, src, dst, ignoreMissing = False):
""" """
if filenames: if filenames:
for filename in filenames: for filename in filenames:
move_between_sets(set(read_lines(filename)), src, dst, filename, ignoreMissing) move_between_sets(set(read_lines(filename)), src, dst, filename)
def move_serialization(src, dst): def move_serialization(src, dst):
"""Moves all members matching serialization API signatures between given sets. """Moves all members matching serialization API signatures between given sets.
@@ -152,6 +179,17 @@ def move_serialization(src, dst):
regex = re.compile(r'.*->(' + '|'.join(serialization_patterns) + r')$') regex = re.compile(r'.*->(' + '|'.join(serialization_patterns) + r')$')
move_between_sets(filter(lambda api: regex.match(api), src), src, dst) move_between_sets(filter(lambda api: regex.match(api), src), src, dst)
def move_from_packages(packages, src, dst):
"""Moves all members of given package names from one set to another.
Args:
packages (list): List of string package names.
src (set): Set that will be searched for API matching one of the given
package names. Surch API will be removed from the set.
dst (set): Set that matching API will be moved to.
"""
move_between_sets(filter(lambda api: get_package_name(api) in packages, src), src, dst)
def main(argv): def main(argv):
args = get_args() args = get_args()
@@ -171,15 +209,17 @@ def main(argv):
# Read all files which manually assign members to specific lists. # Read all files which manually assign members to specific lists.
move_from_files(args.input_whitelists, uncategorized, whitelist) move_from_files(args.input_whitelists, uncategorized, whitelist)
move_from_files(args.input_light_greylists, uncategorized, light_greylist) move_from_files(args.input_greylists, uncategorized, light_greylist)
move_from_files(args.input_blacklists, uncategorized, blacklist) move_from_files(args.input_blacklists, uncategorized, blacklist)
# Iterate over all uncategorized members and move serialization API to light greylist. # Iterate over all uncategorized members and move serialization API to light greylist.
move_serialization(uncategorized, light_greylist) move_serialization(uncategorized, light_greylist)
# Read dark greylist inputs and move all entries to dark greylist. # Extract package names of members from whitelist and light greylist, which
# Note that the input is the list from P, so we will ignore missing entries. # are assumed to have been finalized at this point. Assign all uncategorized
move_from_files(args.input_dark_greylists, uncategorized, dark_greylist, ignoreMissing=True) # members from the same packages to the dark greylist.
dark_greylist_packages = all_package_names(whitelist, light_greylist)
move_from_packages(dark_greylist_packages, uncategorized, dark_greylist)
# Assign all uncategorized members to the blacklist. # Assign all uncategorized members to the blacklist.
move_all(uncategorized, blacklist) move_all(uncategorized, blacklist)

View File

@@ -38,6 +38,33 @@ class TestHiddenapiListGeneration(unittest.TestCase):
with self.assertRaises(AssertionError) as ar: with self.assertRaises(AssertionError) as ar:
move_between_sets(set([1, 4]), A, B) move_between_sets(set([1, 4]), A, B)
def test_get_package_name(self):
self.assertEqual(get_package_name("Ljava/lang/String;->clone()V"), "Ljava/lang/")
def test_get_package_name_fail_no_arrow(self):
with self.assertRaises(AssertionError) as ar:
get_package_name("Ljava/lang/String;-clone()V")
with self.assertRaises(AssertionError) as ar:
get_package_name("Ljava/lang/String;>clone()V")
with self.assertRaises(AssertionError) as ar:
get_package_name("Ljava/lang/String;__clone()V")
def test_get_package_name_fail_no_package(self):
with self.assertRaises(AssertionError) as ar:
get_package_name("LString;->clone()V")
def test_all_package_names(self):
self.assertEqual(all_package_names(), set())
self.assertEqual(all_package_names(set(["Lfoo/Bar;->baz()V"])), set(["Lfoo/"]))
self.assertEqual(
all_package_names(set(["Lfoo/Bar;->baz()V", "Lfoo/BarX;->bazx()I"])),
set(["Lfoo/"]))
self.assertEqual(
all_package_names(
set(["Lfoo/Bar;->baz()V"]),
set(["Lfoo/BarX;->bazx()I", "Labc/xyz/Mno;->ijk()J"])),
set(["Lfoo/", "Labc/xyz/"]))
def test_move_all(self): def test_move_all(self):
src = set([ "abc", "xyz" ]) src = set([ "abc", "xyz" ])
dst = set([ "def" ]) dst = set([ "def" ])
@@ -45,5 +72,18 @@ class TestHiddenapiListGeneration(unittest.TestCase):
self.assertEqual(src, set()) self.assertEqual(src, set())
self.assertEqual(dst, set([ "abc", "def", "xyz" ])) self.assertEqual(dst, set([ "abc", "def", "xyz" ]))
def test_move_from_packages(self):
src = set([ "Lfoo/bar/ClassA;->abc()J", # will be moved
"Lfoo/bar/ClassA;->def()J", # will be moved
"Lcom/pkg/example/ClassD;->ijk:J", # not moved: different package
"Lfoo/bar/xyz/ClassC;->xyz()Z" ]) # not moved: subpackage
dst = set()
packages = set([ "Lfoo/bar/" ])
move_from_packages(packages, src, dst)
self.assertEqual(
src, set([ "Lfoo/bar/xyz/ClassC;->xyz()Z", "Lcom/pkg/example/ClassD;->ijk:J" ]))
self.assertEqual(
dst, set([ "Lfoo/bar/ClassA;->abc()J", "Lfoo/bar/ClassA;->def()J" ]))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()