1*c2e18aaaSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*c2e18aaaSAndroid Build Coastguard Worker# 3*c2e18aaaSAndroid Build Coastguard Worker# Copyright 2020 - The Android Open Source Project 4*c2e18aaaSAndroid Build Coastguard Worker# 5*c2e18aaaSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*c2e18aaaSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*c2e18aaaSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*c2e18aaaSAndroid Build Coastguard Worker# 9*c2e18aaaSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*c2e18aaaSAndroid Build Coastguard Worker# 11*c2e18aaaSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*c2e18aaaSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*c2e18aaaSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*c2e18aaaSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*c2e18aaaSAndroid Build Coastguard Worker# limitations under the License. 16*c2e18aaaSAndroid Build Coastguard Worker 17*c2e18aaaSAndroid Build Coastguard Worker"""Separate the sources from multiple projects.""" 18*c2e18aaaSAndroid Build Coastguard Worker 19*c2e18aaaSAndroid Build Coastguard Workerimport logging 20*c2e18aaaSAndroid Build Coastguard Workerimport os 21*c2e18aaaSAndroid Build Coastguard Workerimport shutil 22*c2e18aaaSAndroid Build Coastguard Worker 23*c2e18aaaSAndroid Build Coastguard Workerfrom pathlib import Path 24*c2e18aaaSAndroid Build Coastguard Worker 25*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen import constant 26*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen.idea import iml 27*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen.lib import common_util 28*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen.lib import project_config 29*c2e18aaaSAndroid Build Coastguard Worker 30*c2e18aaaSAndroid Build Coastguard Worker_KEY_SOURCE_PATH = 'source_folder_path' 31*c2e18aaaSAndroid Build Coastguard Worker_KEY_TEST_PATH = 'test_folder_path' 32*c2e18aaaSAndroid Build Coastguard Worker_SOURCE_FOLDERS = [_KEY_SOURCE_PATH, _KEY_TEST_PATH] 33*c2e18aaaSAndroid Build Coastguard Worker_KEY_SRCJAR_PATH = 'srcjar_path' 34*c2e18aaaSAndroid Build Coastguard Worker_KEY_R_PATH = 'r_java_path' 35*c2e18aaaSAndroid Build Coastguard Worker_KEY_JAR_PATH = 'jar_path' 36*c2e18aaaSAndroid Build Coastguard Worker_EXCLUDE_ITEM = '\n <excludeFolder url="file://%s" />' 37*c2e18aaaSAndroid Build Coastguard Worker# Temporarily exclude test-dump and src_stub folders to prevent symbols from 38*c2e18aaaSAndroid Build Coastguard Worker# resolving failure by incorrect reference. These two folders should be removed 39*c2e18aaaSAndroid Build Coastguard Worker# after b/136982078 is resolved. 40*c2e18aaaSAndroid Build Coastguard Worker_EXCLUDE_FOLDERS = ['.idea', '.repo', 'art', 'bionic', 'bootable', 'build', 41*c2e18aaaSAndroid Build Coastguard Worker 'dalvik', 'developers', 'device', 'hardware', 'kernel', 42*c2e18aaaSAndroid Build Coastguard Worker 'libnativehelper', 'pdk', 'prebuilts', 'sdk', 'system', 43*c2e18aaaSAndroid Build Coastguard Worker 'toolchain', 'tools', 'vendor', 'out', 'external', 44*c2e18aaaSAndroid Build Coastguard Worker 'art/tools/ahat/src/test-dump', 45*c2e18aaaSAndroid Build Coastguard Worker 'cts/common/device-side/device-info/src_stub', 46*c2e18aaaSAndroid Build Coastguard Worker 'external/gson/gson/src/main/java' 47*c2e18aaaSAndroid Build Coastguard Worker ] 48*c2e18aaaSAndroid Build Coastguard Worker_PERMISSION_DEFINED_PATH = ('frameworks/base/core/res/framework-res/' 49*c2e18aaaSAndroid Build Coastguard Worker 'android_common/gen/') 50*c2e18aaaSAndroid Build Coastguard Worker_ANDROID = 'android' 51*c2e18aaaSAndroid Build Coastguard Worker_R = 'R' 52*c2e18aaaSAndroid Build Coastguard Worker 53*c2e18aaaSAndroid Build Coastguard Worker 54*c2e18aaaSAndroid Build Coastguard Workerclass ProjectSplitter: 55*c2e18aaaSAndroid Build Coastguard Worker """Splits the sources from multiple projects. 56*c2e18aaaSAndroid Build Coastguard Worker 57*c2e18aaaSAndroid Build Coastguard Worker It's a specific solution to deal with the source folders in multiple 58*c2e18aaaSAndroid Build Coastguard Worker project case. Since the IntelliJ does not allow duplicate source folders, 59*c2e18aaaSAndroid Build Coastguard Worker AIDEGen needs to separate the source folders for each project. The single 60*c2e18aaaSAndroid Build Coastguard Worker project case has no different with current structure. 61*c2e18aaaSAndroid Build Coastguard Worker 62*c2e18aaaSAndroid Build Coastguard Worker Usage: 63*c2e18aaaSAndroid Build Coastguard Worker project_splitter = ProjectSplitter(projects) 64*c2e18aaaSAndroid Build Coastguard Worker 65*c2e18aaaSAndroid Build Coastguard Worker # Find the dependencies between the projects. 66*c2e18aaaSAndroid Build Coastguard Worker project_splitter.get_dependencies() 67*c2e18aaaSAndroid Build Coastguard Worker 68*c2e18aaaSAndroid Build Coastguard Worker # Clear the source folders for each project. 69*c2e18aaaSAndroid Build Coastguard Worker project_splitter.revise_source_folders() 70*c2e18aaaSAndroid Build Coastguard Worker 71*c2e18aaaSAndroid Build Coastguard Worker Attributes: 72*c2e18aaaSAndroid Build Coastguard Worker _projects: A list of ProjectInfo. 73*c2e18aaaSAndroid Build Coastguard Worker _all_srcs: A dictionary contains all sources of multiple projects. 74*c2e18aaaSAndroid Build Coastguard Worker e.g. 75*c2e18aaaSAndroid Build Coastguard Worker { 76*c2e18aaaSAndroid Build Coastguard Worker 'module_name': 'test', 77*c2e18aaaSAndroid Build Coastguard Worker 'path': ['path/to/module'], 78*c2e18aaaSAndroid Build Coastguard Worker 'srcs': ['src_folder1', 'src_folder2'], 79*c2e18aaaSAndroid Build Coastguard Worker 'tests': ['test_folder1', 'test_folder2'] 80*c2e18aaaSAndroid Build Coastguard Worker 'jars': ['jar1.jar'], 81*c2e18aaaSAndroid Build Coastguard Worker 'srcjars': ['1.srcjar', '2.srcjar'], 82*c2e18aaaSAndroid Build Coastguard Worker 'dependencies': ['framework_srcjars', 'base'], 83*c2e18aaaSAndroid Build Coastguard Worker 'iml_name': '/abs/path/to/iml.iml' 84*c2e18aaaSAndroid Build Coastguard Worker } 85*c2e18aaaSAndroid Build Coastguard Worker _framework_exist: A boolean, True if framework is one of the projects. 86*c2e18aaaSAndroid Build Coastguard Worker _framework_iml: A string, the name of the framework's iml. 87*c2e18aaaSAndroid Build Coastguard Worker _full_repo: A boolean, True if loading with full Android sources. 88*c2e18aaaSAndroid Build Coastguard Worker _full_repo_iml: A string, the name of the Android folder's iml. 89*c2e18aaaSAndroid Build Coastguard Worker _permission_r_srcjar: A string, the absolute path of R.srcjar file where 90*c2e18aaaSAndroid Build Coastguard Worker the permission relative constants are defined. 91*c2e18aaaSAndroid Build Coastguard Worker _permission_aapt2: A string, the absolute path of aapt2/R directory 92*c2e18aaaSAndroid Build Coastguard Worker where the permission relative constants are defined. 93*c2e18aaaSAndroid Build Coastguard Worker """ 94*c2e18aaaSAndroid Build Coastguard Worker def __init__(self, projects): 95*c2e18aaaSAndroid Build Coastguard Worker """ProjectSplitter initialize. 96*c2e18aaaSAndroid Build Coastguard Worker 97*c2e18aaaSAndroid Build Coastguard Worker Args: 98*c2e18aaaSAndroid Build Coastguard Worker projects: A list of ProjectInfo object. 99*c2e18aaaSAndroid Build Coastguard Worker """ 100*c2e18aaaSAndroid Build Coastguard Worker self._projects = projects 101*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs = dict(projects[0].source_path) 102*c2e18aaaSAndroid Build Coastguard Worker self._framework_iml = None 103*c2e18aaaSAndroid Build Coastguard Worker self._framework_exist = any( 104*c2e18aaaSAndroid Build Coastguard Worker {p.project_relative_path == constant.FRAMEWORK_PATH 105*c2e18aaaSAndroid Build Coastguard Worker for p in self._projects}) 106*c2e18aaaSAndroid Build Coastguard Worker if self._framework_exist: 107*c2e18aaaSAndroid Build Coastguard Worker self._framework_iml = iml.IMLGenerator.get_unique_iml_name( 108*c2e18aaaSAndroid Build Coastguard Worker os.path.join(common_util.get_android_root_dir(), 109*c2e18aaaSAndroid Build Coastguard Worker constant.FRAMEWORK_PATH)) 110*c2e18aaaSAndroid Build Coastguard Worker self._full_repo = project_config.ProjectConfig.get_instance().full_repo 111*c2e18aaaSAndroid Build Coastguard Worker if self._full_repo: 112*c2e18aaaSAndroid Build Coastguard Worker self._full_repo_iml = os.path.basename( 113*c2e18aaaSAndroid Build Coastguard Worker common_util.get_android_root_dir()) 114*c2e18aaaSAndroid Build Coastguard Worker self._permission_r_srcjar = _get_permission_r_srcjar_rel_path() 115*c2e18aaaSAndroid Build Coastguard Worker self._permission_aapt2 = _get_permission_aapt2_rel_path() 116*c2e18aaaSAndroid Build Coastguard Worker 117*c2e18aaaSAndroid Build Coastguard Worker def revise_source_folders(self): 118*c2e18aaaSAndroid Build Coastguard Worker """Resets the source folders of each project. 119*c2e18aaaSAndroid Build Coastguard Worker 120*c2e18aaaSAndroid Build Coastguard Worker There should be no duplicate source root path in IntelliJ. The issue 121*c2e18aaaSAndroid Build Coastguard Worker doesn't happen in single project case. Once users choose multiple 122*c2e18aaaSAndroid Build Coastguard Worker projects, there could be several same source paths of different 123*c2e18aaaSAndroid Build Coastguard Worker projects. In order to prevent that, we should remove the source paths 124*c2e18aaaSAndroid Build Coastguard Worker in dependencies.iml which are duplicate with the paths in [module].iml 125*c2e18aaaSAndroid Build Coastguard Worker files. 126*c2e18aaaSAndroid Build Coastguard Worker 127*c2e18aaaSAndroid Build Coastguard Worker Steps to prevent the duplicate source root path in IntelliJ: 128*c2e18aaaSAndroid Build Coastguard Worker 1. Copy all sources from sub-projects to main project. 129*c2e18aaaSAndroid Build Coastguard Worker 2. Delete the source and test folders which are not under the 130*c2e18aaaSAndroid Build Coastguard Worker sub-projects. 131*c2e18aaaSAndroid Build Coastguard Worker 3. Delete the sub-projects' source and test paths from the main project. 132*c2e18aaaSAndroid Build Coastguard Worker """ 133*c2e18aaaSAndroid Build Coastguard Worker self._collect_all_srcs() 134*c2e18aaaSAndroid Build Coastguard Worker self._keep_local_sources() 135*c2e18aaaSAndroid Build Coastguard Worker self._remove_duplicate_sources() 136*c2e18aaaSAndroid Build Coastguard Worker 137*c2e18aaaSAndroid Build Coastguard Worker def _collect_all_srcs(self): 138*c2e18aaaSAndroid Build Coastguard Worker """Copies all projects' sources to a dictionary.""" 139*c2e18aaaSAndroid Build Coastguard Worker for project in self._projects[1:]: 140*c2e18aaaSAndroid Build Coastguard Worker for key, value in project.source_path.items(): 141*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[key].update(value) 142*c2e18aaaSAndroid Build Coastguard Worker 143*c2e18aaaSAndroid Build Coastguard Worker def _keep_local_sources(self): 144*c2e18aaaSAndroid Build Coastguard Worker """Removes source folders which are not under the project's path. 145*c2e18aaaSAndroid Build Coastguard Worker 146*c2e18aaaSAndroid Build Coastguard Worker 1. Remove the source folders which are not under the project. 147*c2e18aaaSAndroid Build Coastguard Worker 2. Remove the duplicate project's source folders from the _all_srcs. 148*c2e18aaaSAndroid Build Coastguard Worker """ 149*c2e18aaaSAndroid Build Coastguard Worker for project in self._projects: 150*c2e18aaaSAndroid Build Coastguard Worker srcs = project.source_path 151*c2e18aaaSAndroid Build Coastguard Worker relpath = project.project_relative_path 152*c2e18aaaSAndroid Build Coastguard Worker is_root = not relpath 153*c2e18aaaSAndroid Build Coastguard Worker for key in _SOURCE_FOLDERS: 154*c2e18aaaSAndroid Build Coastguard Worker srcs[key] = {s for s in srcs[key] 155*c2e18aaaSAndroid Build Coastguard Worker if common_util.is_source_under_relative_path( 156*c2e18aaaSAndroid Build Coastguard Worker s, relpath) or is_root} 157*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[key] -= srcs[key] 158*c2e18aaaSAndroid Build Coastguard Worker 159*c2e18aaaSAndroid Build Coastguard Worker def _remove_duplicate_sources(self): 160*c2e18aaaSAndroid Build Coastguard Worker """Removes the duplicate source folders from each sub-project. 161*c2e18aaaSAndroid Build Coastguard Worker 162*c2e18aaaSAndroid Build Coastguard Worker Priority processing with the longest path length, e.g. 163*c2e18aaaSAndroid Build Coastguard Worker frameworks/base/packages/SettingsLib must have priority over 164*c2e18aaaSAndroid Build Coastguard Worker frameworks/base. 165*c2e18aaaSAndroid Build Coastguard Worker (b/160303006): Remove the parent project's source and test paths under 166*c2e18aaaSAndroid Build Coastguard Worker the child's project path. 167*c2e18aaaSAndroid Build Coastguard Worker """ 168*c2e18aaaSAndroid Build Coastguard Worker root = common_util.get_android_root_dir() 169*c2e18aaaSAndroid Build Coastguard Worker projects = sorted(self._projects, key=lambda k: len( 170*c2e18aaaSAndroid Build Coastguard Worker k.project_relative_path), reverse=True) 171*c2e18aaaSAndroid Build Coastguard Worker for child in projects: 172*c2e18aaaSAndroid Build Coastguard Worker for parent in self._projects: 173*c2e18aaaSAndroid Build Coastguard Worker is_root = not parent.project_relative_path 174*c2e18aaaSAndroid Build Coastguard Worker if parent is child: 175*c2e18aaaSAndroid Build Coastguard Worker continue 176*c2e18aaaSAndroid Build Coastguard Worker if (common_util.is_source_under_relative_path( 177*c2e18aaaSAndroid Build Coastguard Worker child.project_relative_path, 178*c2e18aaaSAndroid Build Coastguard Worker parent.project_relative_path) or is_root): 179*c2e18aaaSAndroid Build Coastguard Worker for key in _SOURCE_FOLDERS: 180*c2e18aaaSAndroid Build Coastguard Worker parent.source_path[key] -= child.source_path[key] 181*c2e18aaaSAndroid Build Coastguard Worker rm_paths = _remove_child_duplicate_sources_from_parent( 182*c2e18aaaSAndroid Build Coastguard Worker child, parent.source_path[key], root) 183*c2e18aaaSAndroid Build Coastguard Worker parent.source_path[key] -= rm_paths 184*c2e18aaaSAndroid Build Coastguard Worker 185*c2e18aaaSAndroid Build Coastguard Worker def get_dependencies(self): 186*c2e18aaaSAndroid Build Coastguard Worker """Gets the dependencies between the projects. 187*c2e18aaaSAndroid Build Coastguard Worker 188*c2e18aaaSAndroid Build Coastguard Worker Check if the current project's source folder exists in other projects. 189*c2e18aaaSAndroid Build Coastguard Worker If so, the current project is a dependency module to the other. 190*c2e18aaaSAndroid Build Coastguard Worker """ 191*c2e18aaaSAndroid Build Coastguard Worker projects = sorted(self._projects, key=lambda k: len( 192*c2e18aaaSAndroid Build Coastguard Worker k.project_relative_path)) 193*c2e18aaaSAndroid Build Coastguard Worker for project in projects: 194*c2e18aaaSAndroid Build Coastguard Worker proj_path = project.project_relative_path 195*c2e18aaaSAndroid Build Coastguard Worker project.dependencies = [constant.FRAMEWORK_SRCJARS] 196*c2e18aaaSAndroid Build Coastguard Worker if self._framework_exist and proj_path != constant.FRAMEWORK_PATH: 197*c2e18aaaSAndroid Build Coastguard Worker project.dependencies.append(self._framework_iml) 198*c2e18aaaSAndroid Build Coastguard Worker if self._full_repo and proj_path: 199*c2e18aaaSAndroid Build Coastguard Worker project.dependencies.append(self._full_repo_iml) 200*c2e18aaaSAndroid Build Coastguard Worker srcs = (project.source_path[_KEY_SOURCE_PATH] 201*c2e18aaaSAndroid Build Coastguard Worker | project.source_path[_KEY_TEST_PATH]) 202*c2e18aaaSAndroid Build Coastguard Worker dep_projects = sorted(self._projects, key=lambda k: len( 203*c2e18aaaSAndroid Build Coastguard Worker k.project_relative_path)) 204*c2e18aaaSAndroid Build Coastguard Worker for dep_proj in dep_projects: 205*c2e18aaaSAndroid Build Coastguard Worker dep_path = dep_proj.project_relative_path 206*c2e18aaaSAndroid Build Coastguard Worker is_root = not dep_path 207*c2e18aaaSAndroid Build Coastguard Worker is_child = common_util.is_source_under_relative_path(dep_path, 208*c2e18aaaSAndroid Build Coastguard Worker proj_path) 209*c2e18aaaSAndroid Build Coastguard Worker is_dep = any({s for s in srcs 210*c2e18aaaSAndroid Build Coastguard Worker if common_util.is_source_under_relative_path( 211*c2e18aaaSAndroid Build Coastguard Worker s, dep_path) or is_root}) 212*c2e18aaaSAndroid Build Coastguard Worker if dep_proj is project or is_child or not is_dep: 213*c2e18aaaSAndroid Build Coastguard Worker continue 214*c2e18aaaSAndroid Build Coastguard Worker dep = iml.IMLGenerator.get_unique_iml_name(os.path.join( 215*c2e18aaaSAndroid Build Coastguard Worker common_util.get_android_root_dir(), dep_path)) 216*c2e18aaaSAndroid Build Coastguard Worker if dep not in project.dependencies: 217*c2e18aaaSAndroid Build Coastguard Worker project.dependencies.append(dep) 218*c2e18aaaSAndroid Build Coastguard Worker project.dependencies.append(constant.KEY_DEPENDENCIES) 219*c2e18aaaSAndroid Build Coastguard Worker 220*c2e18aaaSAndroid Build Coastguard Worker def gen_framework_srcjars_iml(self): 221*c2e18aaaSAndroid Build Coastguard Worker """Generates the framework_srcjars.iml. 222*c2e18aaaSAndroid Build Coastguard Worker 223*c2e18aaaSAndroid Build Coastguard Worker Create the iml file with only the srcjars of module framework-all. These 224*c2e18aaaSAndroid Build Coastguard Worker srcjars will be separated from the modules under frameworks/base. 225*c2e18aaaSAndroid Build Coastguard Worker 226*c2e18aaaSAndroid Build Coastguard Worker Returns: 227*c2e18aaaSAndroid Build Coastguard Worker A string of the framework_srcjars.iml's absolute path. 228*c2e18aaaSAndroid Build Coastguard Worker """ 229*c2e18aaaSAndroid Build Coastguard Worker self._remove_permission_definition_srcjar_path() 230*c2e18aaaSAndroid Build Coastguard Worker mod = dict(self._projects[0].dep_modules[constant.FRAMEWORK_ALL]) 231*c2e18aaaSAndroid Build Coastguard Worker mod[constant.KEY_DEPENDENCIES] = [] 232*c2e18aaaSAndroid Build Coastguard Worker mod[constant.KEY_IML_NAME] = constant.FRAMEWORK_SRCJARS 233*c2e18aaaSAndroid Build Coastguard Worker if self._framework_exist: 234*c2e18aaaSAndroid Build Coastguard Worker mod[constant.KEY_DEPENDENCIES].append(self._framework_iml) 235*c2e18aaaSAndroid Build Coastguard Worker if self._full_repo: 236*c2e18aaaSAndroid Build Coastguard Worker mod[constant.KEY_DEPENDENCIES].append(self._full_repo_iml) 237*c2e18aaaSAndroid Build Coastguard Worker mod[constant.KEY_DEPENDENCIES].append(constant.KEY_DEPENDENCIES) 238*c2e18aaaSAndroid Build Coastguard Worker permission_src = self._get_permission_defined_source_path() 239*c2e18aaaSAndroid Build Coastguard Worker if permission_src: 240*c2e18aaaSAndroid Build Coastguard Worker mod[constant.KEY_SRCS] = [permission_src] 241*c2e18aaaSAndroid Build Coastguard Worker srcjar_dict = {constant.KEY_DEP_SRCS: True, 242*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_SRCJARS: True, 243*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_DEPENDENCIES: True} 244*c2e18aaaSAndroid Build Coastguard Worker else: 245*c2e18aaaSAndroid Build Coastguard Worker logging.warning('The permission definition relative paths are ' 246*c2e18aaaSAndroid Build Coastguard Worker 'missing.') 247*c2e18aaaSAndroid Build Coastguard Worker srcjar_dict = {constant.KEY_SRCJARS: True, 248*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_DEPENDENCIES: True} 249*c2e18aaaSAndroid Build Coastguard Worker framework_srcjars_iml = iml.IMLGenerator(mod) 250*c2e18aaaSAndroid Build Coastguard Worker framework_srcjars_iml.create(srcjar_dict) 251*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[_KEY_SRCJAR_PATH] -= set(mod.get(constant.KEY_SRCJARS, 252*c2e18aaaSAndroid Build Coastguard Worker [])) 253*c2e18aaaSAndroid Build Coastguard Worker return framework_srcjars_iml.iml_path 254*c2e18aaaSAndroid Build Coastguard Worker 255*c2e18aaaSAndroid Build Coastguard Worker def _get_permission_defined_source_path(self): 256*c2e18aaaSAndroid Build Coastguard Worker """Gets the source path where permission relative constants are defined. 257*c2e18aaaSAndroid Build Coastguard Worker 258*c2e18aaaSAndroid Build Coastguard Worker For the definition permission constants, the priority is, 259*c2e18aaaSAndroid Build Coastguard Worker 1) If framework-res/android_common/gen/aapt2/R directory exists, return 260*c2e18aaaSAndroid Build Coastguard Worker it. 261*c2e18aaaSAndroid Build Coastguard Worker 2) If the framework-res/android_common/gen/android/R.srcjar file exists, 262*c2e18aaaSAndroid Build Coastguard Worker unzip it to 'aidegen_r.srcjar' folder and return the path. 263*c2e18aaaSAndroid Build Coastguard Worker 264*c2e18aaaSAndroid Build Coastguard Worker Returns: 265*c2e18aaaSAndroid Build Coastguard Worker A string of the path of aapt2/R or android/aidegen_r.srcjar folder, 266*c2e18aaaSAndroid Build Coastguard Worker else None. 267*c2e18aaaSAndroid Build Coastguard Worker """ 268*c2e18aaaSAndroid Build Coastguard Worker if os.path.isdir(self._permission_aapt2): 269*c2e18aaaSAndroid Build Coastguard Worker return self._permission_aapt2 270*c2e18aaaSAndroid Build Coastguard Worker if os.path.isfile(self._permission_r_srcjar): 271*c2e18aaaSAndroid Build Coastguard Worker dest = os.path.join( 272*c2e18aaaSAndroid Build Coastguard Worker os.path.dirname(self._permission_r_srcjar), 273*c2e18aaaSAndroid Build Coastguard Worker ''.join([constant.UNZIP_SRCJAR_PATH_HEAD, 274*c2e18aaaSAndroid Build Coastguard Worker os.path.basename(self._permission_r_srcjar).lower()])) 275*c2e18aaaSAndroid Build Coastguard Worker if os.path.isdir(dest): 276*c2e18aaaSAndroid Build Coastguard Worker shutil.rmtree(dest) 277*c2e18aaaSAndroid Build Coastguard Worker common_util.unzip_file(self._permission_r_srcjar, dest) 278*c2e18aaaSAndroid Build Coastguard Worker return dest 279*c2e18aaaSAndroid Build Coastguard Worker return None 280*c2e18aaaSAndroid Build Coastguard Worker 281*c2e18aaaSAndroid Build Coastguard Worker def _gen_dependencies_iml(self): 282*c2e18aaaSAndroid Build Coastguard Worker """Generates the dependencies.iml.""" 283*c2e18aaaSAndroid Build Coastguard Worker rel_project_soong_paths = self._get_rel_project_soong_paths() 284*c2e18aaaSAndroid Build Coastguard Worker self._unzip_all_scrjars() 285*c2e18aaaSAndroid Build Coastguard Worker mod = { 286*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_SRCS: _get_real_dependencies_jars( 287*c2e18aaaSAndroid Build Coastguard Worker rel_project_soong_paths, self._all_srcs[_KEY_SOURCE_PATH]), 288*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_TESTS: _get_real_dependencies_jars( 289*c2e18aaaSAndroid Build Coastguard Worker rel_project_soong_paths, self._all_srcs[_KEY_TEST_PATH]), 290*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_JARS: _get_real_dependencies_jars( 291*c2e18aaaSAndroid Build Coastguard Worker rel_project_soong_paths, self._all_srcs[_KEY_JAR_PATH]), 292*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_SRCJARS: _get_real_dependencies_jars( 293*c2e18aaaSAndroid Build Coastguard Worker rel_project_soong_paths, 294*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[_KEY_R_PATH] | self._all_srcs[_KEY_SRCJAR_PATH]), 295*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_DEPENDENCIES: _get_real_dependencies_jars( 296*c2e18aaaSAndroid Build Coastguard Worker rel_project_soong_paths, [constant.FRAMEWORK_SRCJARS]), 297*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_PATH: [self._projects[0].project_relative_path], 298*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_MODULE_NAME: constant.KEY_DEPENDENCIES, 299*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_IML_NAME: constant.KEY_DEPENDENCIES 300*c2e18aaaSAndroid Build Coastguard Worker } 301*c2e18aaaSAndroid Build Coastguard Worker if self._framework_exist: 302*c2e18aaaSAndroid Build Coastguard Worker mod[constant.KEY_DEPENDENCIES].append(self._framework_iml) 303*c2e18aaaSAndroid Build Coastguard Worker if self._full_repo: 304*c2e18aaaSAndroid Build Coastguard Worker mod[constant.KEY_DEPENDENCIES].append(self._full_repo_iml) 305*c2e18aaaSAndroid Build Coastguard Worker dep_iml = iml.IMLGenerator(mod) 306*c2e18aaaSAndroid Build Coastguard Worker dep_iml.create({constant.KEY_DEP_SRCS: True, 307*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_SRCJARS: True, 308*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_JARS: True, 309*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_DEPENDENCIES: True}) 310*c2e18aaaSAndroid Build Coastguard Worker 311*c2e18aaaSAndroid Build Coastguard Worker def _unzip_all_scrjars(self): 312*c2e18aaaSAndroid Build Coastguard Worker """Unzips all scrjar files to a specific folder 'aidegen_r.srcjar'. 313*c2e18aaaSAndroid Build Coastguard Worker 314*c2e18aaaSAndroid Build Coastguard Worker For some versions of IntelliJ no more supports unzipping srcjar files 315*c2e18aaaSAndroid Build Coastguard Worker automatically, we have to unzip it to a 'aidegen_r.srcjar' directory. 316*c2e18aaaSAndroid Build Coastguard Worker The rules of the unzip process are, 317*c2e18aaaSAndroid Build Coastguard Worker 1) If it's a aapt2/R type jar or other directory type sources, add them 318*c2e18aaaSAndroid Build Coastguard Worker into self._all_srcs[_KEY_SOURCE_PATH]. 319*c2e18aaaSAndroid Build Coastguard Worker 2) If it's an R.srcjar file, check if the same path of aapt2/R directory 320*c2e18aaaSAndroid Build Coastguard Worker exists if so add aapt2/R path into the 321*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[_KEY_SOURCE_PATH], otherwise unzip R.srcjar into 322*c2e18aaaSAndroid Build Coastguard Worker the 'aidegen_r.srcjar' directory and add the unzipped path into 323*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[_KEY_SOURCE_PATH]. 324*c2e18aaaSAndroid Build Coastguard Worker """ 325*c2e18aaaSAndroid Build Coastguard Worker sjars = self._all_srcs[_KEY_R_PATH] | self._all_srcs[_KEY_SRCJAR_PATH] 326*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[_KEY_R_PATH] = set() 327*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[_KEY_SRCJAR_PATH] = set() 328*c2e18aaaSAndroid Build Coastguard Worker for sjar in sjars: 329*c2e18aaaSAndroid Build Coastguard Worker if not os.path.exists(sjar): 330*c2e18aaaSAndroid Build Coastguard Worker continue 331*c2e18aaaSAndroid Build Coastguard Worker if os.path.isdir(sjar): 332*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[_KEY_SOURCE_PATH].add(sjar) 333*c2e18aaaSAndroid Build Coastguard Worker continue 334*c2e18aaaSAndroid Build Coastguard Worker sjar_dir = os.path.dirname(sjar) 335*c2e18aaaSAndroid Build Coastguard Worker sjar_name = os.path.basename(sjar).lower() 336*c2e18aaaSAndroid Build Coastguard Worker aapt2 = os.path.join( 337*c2e18aaaSAndroid Build Coastguard Worker os.path.dirname(sjar_dir), constant.NAME_AAPT2, _R) 338*c2e18aaaSAndroid Build Coastguard Worker if os.path.isdir(aapt2): 339*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[_KEY_SOURCE_PATH].add(aapt2) 340*c2e18aaaSAndroid Build Coastguard Worker continue 341*c2e18aaaSAndroid Build Coastguard Worker dest = os.path.join( 342*c2e18aaaSAndroid Build Coastguard Worker sjar_dir, ''.join([constant.UNZIP_SRCJAR_PATH_HEAD, sjar_name])) 343*c2e18aaaSAndroid Build Coastguard Worker if os.path.isdir(dest): 344*c2e18aaaSAndroid Build Coastguard Worker shutil.rmtree(dest) 345*c2e18aaaSAndroid Build Coastguard Worker common_util.unzip_file(sjar, dest) 346*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[_KEY_SOURCE_PATH].add(dest) 347*c2e18aaaSAndroid Build Coastguard Worker 348*c2e18aaaSAndroid Build Coastguard Worker def gen_projects_iml(self): 349*c2e18aaaSAndroid Build Coastguard Worker """Generates the projects' iml file.""" 350*c2e18aaaSAndroid Build Coastguard Worker root_path = common_util.get_android_root_dir() 351*c2e18aaaSAndroid Build Coastguard Worker excludes = project_config.ProjectConfig.get_instance().exclude_paths 352*c2e18aaaSAndroid Build Coastguard Worker for project in self._projects: 353*c2e18aaaSAndroid Build Coastguard Worker relpath = project.project_relative_path 354*c2e18aaaSAndroid Build Coastguard Worker exclude_folders = [] 355*c2e18aaaSAndroid Build Coastguard Worker if not relpath: 356*c2e18aaaSAndroid Build Coastguard Worker exclude_folders.extend(get_exclude_content(root_path)) 357*c2e18aaaSAndroid Build Coastguard Worker if excludes: 358*c2e18aaaSAndroid Build Coastguard Worker exclude_folders.extend(get_exclude_content(root_path, excludes)) 359*c2e18aaaSAndroid Build Coastguard Worker mod_info = { 360*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_EXCLUDES: ''.join(exclude_folders), 361*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_SRCS: project.source_path[_KEY_SOURCE_PATH], 362*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_TESTS: project.source_path[_KEY_TEST_PATH], 363*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_DEPENDENCIES: project.dependencies, 364*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_PATH: [relpath], 365*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_MODULE_NAME: project.module_name, 366*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_IML_NAME: iml.IMLGenerator.get_unique_iml_name( 367*c2e18aaaSAndroid Build Coastguard Worker str(Path(root_path, relpath))) 368*c2e18aaaSAndroid Build Coastguard Worker } 369*c2e18aaaSAndroid Build Coastguard Worker dep_iml = iml.IMLGenerator(mod_info) 370*c2e18aaaSAndroid Build Coastguard Worker dep_iml.create({constant.KEY_SRCS: True, 371*c2e18aaaSAndroid Build Coastguard Worker constant.KEY_DEPENDENCIES: True}) 372*c2e18aaaSAndroid Build Coastguard Worker project.iml_path = dep_iml.iml_path 373*c2e18aaaSAndroid Build Coastguard Worker self._gen_dependencies_iml() 374*c2e18aaaSAndroid Build Coastguard Worker 375*c2e18aaaSAndroid Build Coastguard Worker def _get_rel_project_soong_paths(self): 376*c2e18aaaSAndroid Build Coastguard Worker """Gets relative projects' paths in 'out/soong/.intermediates' folder. 377*c2e18aaaSAndroid Build Coastguard Worker 378*c2e18aaaSAndroid Build Coastguard Worker Gets relative projects' paths in the 'out/soong/.intermediates' 379*c2e18aaaSAndroid Build Coastguard Worker directory. For example, if the self.projects = ['frameworks/base'] the 380*c2e18aaaSAndroid Build Coastguard Worker returned list should be ['out/soong/.intermediates/frameworks/base/']. 381*c2e18aaaSAndroid Build Coastguard Worker 382*c2e18aaaSAndroid Build Coastguard Worker Returns: 383*c2e18aaaSAndroid Build Coastguard Worker A list of relative projects' paths in out/soong/.intermediates. 384*c2e18aaaSAndroid Build Coastguard Worker """ 385*c2e18aaaSAndroid Build Coastguard Worker out_soong_dir = os.path.relpath(common_util.get_soong_out_path(), 386*c2e18aaaSAndroid Build Coastguard Worker common_util.get_android_root_dir()) 387*c2e18aaaSAndroid Build Coastguard Worker rel_project_soong_paths = [] 388*c2e18aaaSAndroid Build Coastguard Worker for project in self._projects: 389*c2e18aaaSAndroid Build Coastguard Worker relpath = project.project_relative_path 390*c2e18aaaSAndroid Build Coastguard Worker rel_project_soong_paths.append(os.sep.join( 391*c2e18aaaSAndroid Build Coastguard Worker [out_soong_dir, constant.INTERMEDIATES, relpath]) + os.sep) 392*c2e18aaaSAndroid Build Coastguard Worker return rel_project_soong_paths 393*c2e18aaaSAndroid Build Coastguard Worker 394*c2e18aaaSAndroid Build Coastguard Worker def _remove_permission_definition_srcjar_path(self): 395*c2e18aaaSAndroid Build Coastguard Worker """Removes android.Manifest.permission definition srcjar path. 396*c2e18aaaSAndroid Build Coastguard Worker 397*c2e18aaaSAndroid Build Coastguard Worker If framework-res/android_common/gen/aapt2/R directory or 398*c2e18aaaSAndroid Build Coastguard Worker framework-res/android_common/gen/android/R.srcjar file exists in 399*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[_KEY_SRCJAR_PATH], remove them. 400*c2e18aaaSAndroid Build Coastguard Worker """ 401*c2e18aaaSAndroid Build Coastguard Worker if self._permission_aapt2 in self._all_srcs[_KEY_SRCJAR_PATH]: 402*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[_KEY_SRCJAR_PATH].remove(self._permission_aapt2) 403*c2e18aaaSAndroid Build Coastguard Worker if self._permission_r_srcjar in self._all_srcs[_KEY_SRCJAR_PATH]: 404*c2e18aaaSAndroid Build Coastguard Worker self._all_srcs[_KEY_SRCJAR_PATH].remove(self._permission_r_srcjar) 405*c2e18aaaSAndroid Build Coastguard Worker 406*c2e18aaaSAndroid Build Coastguard Worker 407*c2e18aaaSAndroid Build Coastguard Workerdef _get_real_dependencies_jars(list_to_check, list_to_be_checked): 408*c2e18aaaSAndroid Build Coastguard Worker """Gets real dependencies' jar from the input list. 409*c2e18aaaSAndroid Build Coastguard Worker 410*c2e18aaaSAndroid Build Coastguard Worker There are jar files which have the same source codes as the 411*c2e18aaaSAndroid Build Coastguard Worker self.projects should be removed from dependencies. Otherwise these files 412*c2e18aaaSAndroid Build Coastguard Worker will cause the duplicated codes in IDE and lead to issues: b/158583214 is an 413*c2e18aaaSAndroid Build Coastguard Worker example. 414*c2e18aaaSAndroid Build Coastguard Worker 415*c2e18aaaSAndroid Build Coastguard Worker Args: 416*c2e18aaaSAndroid Build Coastguard Worker list_to_check: A list of relative projects' paths in the folder 417*c2e18aaaSAndroid Build Coastguard Worker out/soong/.intermediates to be checked if are contained 418*c2e18aaaSAndroid Build Coastguard Worker in the list_to_be_checked list. 419*c2e18aaaSAndroid Build Coastguard Worker list_to_be_checked: A list of dependencies' paths to be checked. 420*c2e18aaaSAndroid Build Coastguard Worker 421*c2e18aaaSAndroid Build Coastguard Worker Returns: 422*c2e18aaaSAndroid Build Coastguard Worker A list of dependency jar paths after duplicated ones removed. 423*c2e18aaaSAndroid Build Coastguard Worker """ 424*c2e18aaaSAndroid Build Coastguard Worker file_exts = [constant.JAR_EXT] 425*c2e18aaaSAndroid Build Coastguard Worker real_jars = list_to_be_checked.copy() 426*c2e18aaaSAndroid Build Coastguard Worker for jar in list_to_be_checked: 427*c2e18aaaSAndroid Build Coastguard Worker ext = os.path.splitext(jar)[-1] 428*c2e18aaaSAndroid Build Coastguard Worker for check_path in list_to_check: 429*c2e18aaaSAndroid Build Coastguard Worker if check_path in jar and ext in file_exts: 430*c2e18aaaSAndroid Build Coastguard Worker real_jars.remove(jar) 431*c2e18aaaSAndroid Build Coastguard Worker break 432*c2e18aaaSAndroid Build Coastguard Worker return real_jars 433*c2e18aaaSAndroid Build Coastguard Worker 434*c2e18aaaSAndroid Build Coastguard Worker 435*c2e18aaaSAndroid Build Coastguard Workerdef get_exclude_content(root_path, excludes=None): 436*c2e18aaaSAndroid Build Coastguard Worker """Get the exclude folder content list. 437*c2e18aaaSAndroid Build Coastguard Worker 438*c2e18aaaSAndroid Build Coastguard Worker It returns the exclude folders content list. 439*c2e18aaaSAndroid Build Coastguard Worker e.g. 440*c2e18aaaSAndroid Build Coastguard Worker ['<excludeFolder url="file://a/.idea" />', 441*c2e18aaaSAndroid Build Coastguard Worker '<excludeFolder url="file://a/.repo" />'] 442*c2e18aaaSAndroid Build Coastguard Worker 443*c2e18aaaSAndroid Build Coastguard Worker Args: 444*c2e18aaaSAndroid Build Coastguard Worker root_path: Android source file path. 445*c2e18aaaSAndroid Build Coastguard Worker excludes: A list of exclusive directories, the default value is None but 446*c2e18aaaSAndroid Build Coastguard Worker will be assigned to _EXCLUDE_FOLDERS. 447*c2e18aaaSAndroid Build Coastguard Worker 448*c2e18aaaSAndroid Build Coastguard Worker Returns: 449*c2e18aaaSAndroid Build Coastguard Worker String: exclude folder content list. 450*c2e18aaaSAndroid Build Coastguard Worker """ 451*c2e18aaaSAndroid Build Coastguard Worker exclude_items = [] 452*c2e18aaaSAndroid Build Coastguard Worker if not excludes: 453*c2e18aaaSAndroid Build Coastguard Worker excludes = _EXCLUDE_FOLDERS 454*c2e18aaaSAndroid Build Coastguard Worker for folder in excludes: 455*c2e18aaaSAndroid Build Coastguard Worker folder_path = os.path.join(root_path, folder) 456*c2e18aaaSAndroid Build Coastguard Worker if os.path.isdir(folder_path): 457*c2e18aaaSAndroid Build Coastguard Worker exclude_items.append(_EXCLUDE_ITEM % folder_path) 458*c2e18aaaSAndroid Build Coastguard Worker return exclude_items 459*c2e18aaaSAndroid Build Coastguard Worker 460*c2e18aaaSAndroid Build Coastguard Worker 461*c2e18aaaSAndroid Build Coastguard Workerdef _remove_child_duplicate_sources_from_parent(child, parent_sources, root): 462*c2e18aaaSAndroid Build Coastguard Worker """Removes the child's duplicate source folders from the parent source list. 463*c2e18aaaSAndroid Build Coastguard Worker 464*c2e18aaaSAndroid Build Coastguard Worker Remove all the child's subdirectories from the parent's source list if there 465*c2e18aaaSAndroid Build Coastguard Worker is any. 466*c2e18aaaSAndroid Build Coastguard Worker 467*c2e18aaaSAndroid Build Coastguard Worker Args: 468*c2e18aaaSAndroid Build Coastguard Worker child: A child project of ProjectInfo instance. 469*c2e18aaaSAndroid Build Coastguard Worker parent_sources: The parent project sources of the ProjectInfo instance. 470*c2e18aaaSAndroid Build Coastguard Worker root: A string of the Android root. 471*c2e18aaaSAndroid Build Coastguard Worker 472*c2e18aaaSAndroid Build Coastguard Worker Returns: 473*c2e18aaaSAndroid Build Coastguard Worker A set of the sources to be removed. 474*c2e18aaaSAndroid Build Coastguard Worker """ 475*c2e18aaaSAndroid Build Coastguard Worker rm_paths = set() 476*c2e18aaaSAndroid Build Coastguard Worker for path in parent_sources: 477*c2e18aaaSAndroid Build Coastguard Worker if (common_util.is_source_under_relative_path( 478*c2e18aaaSAndroid Build Coastguard Worker os.path.relpath(path, root), child.project_relative_path)): 479*c2e18aaaSAndroid Build Coastguard Worker rm_paths.add(path) 480*c2e18aaaSAndroid Build Coastguard Worker return rm_paths 481*c2e18aaaSAndroid Build Coastguard Worker 482*c2e18aaaSAndroid Build Coastguard Worker 483*c2e18aaaSAndroid Build Coastguard Workerdef _get_permission_aapt2_rel_path(): 484*c2e18aaaSAndroid Build Coastguard Worker """Gets android.Manifest.permission definition srcjar path.""" 485*c2e18aaaSAndroid Build Coastguard Worker out_soong_dir = os.path.relpath(common_util.get_soong_out_path(), 486*c2e18aaaSAndroid Build Coastguard Worker common_util.get_android_root_dir()) 487*c2e18aaaSAndroid Build Coastguard Worker return os.path.join(out_soong_dir, constant.INTERMEDIATES, 488*c2e18aaaSAndroid Build Coastguard Worker _PERMISSION_DEFINED_PATH, constant.NAME_AAPT2, _R) 489*c2e18aaaSAndroid Build Coastguard Worker 490*c2e18aaaSAndroid Build Coastguard Worker 491*c2e18aaaSAndroid Build Coastguard Workerdef _get_permission_r_srcjar_rel_path(): 492*c2e18aaaSAndroid Build Coastguard Worker """Gets android.Manifest.permission definition srcjar path.""" 493*c2e18aaaSAndroid Build Coastguard Worker out_soong_dir = os.path.relpath(common_util.get_soong_out_path(), 494*c2e18aaaSAndroid Build Coastguard Worker common_util.get_android_root_dir()) 495*c2e18aaaSAndroid Build Coastguard Worker return os.path.join(out_soong_dir, constant.INTERMEDIATES, 496*c2e18aaaSAndroid Build Coastguard Worker _PERMISSION_DEFINED_PATH, _ANDROID, 497*c2e18aaaSAndroid Build Coastguard Worker constant.TARGET_R_SRCJAR) 498