xref: /aosp_15_r20/tools/asuite/aidegen/sdk/jdk_table.py (revision c2e18aaa1096c836b086f94603d04f4eb9cf37f5)
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"""Configs the jdk.table.xml.
18*c2e18aaaSAndroid Build Coastguard Worker
19*c2e18aaaSAndroid Build Coastguard WorkerIn order to enable the feature "Attach debugger to Android process" in Android
20*c2e18aaaSAndroid Build Coastguard WorkerStudio or IntelliJ, AIDEGen needs the JDK and Android SDK been set up. The class
21*c2e18aaaSAndroid Build Coastguard WorkerJDKTableXML parses the jdk.table.xml to find the existing JDK and Android SDK
22*c2e18aaaSAndroid Build Coastguard Workerinformation. If they do not exist, AIDEGen will create them.
23*c2e18aaaSAndroid Build Coastguard Worker
24*c2e18aaaSAndroid Build Coastguard Worker    Usage example:
25*c2e18aaaSAndroid Build Coastguard Worker    jdk_table_xml = JDKTableXML(jdk_table_xml_file,
26*c2e18aaaSAndroid Build Coastguard Worker                                jdk_template,
27*c2e18aaaSAndroid Build Coastguard Worker                                default_jdk_path,
28*c2e18aaaSAndroid Build Coastguard Worker                                default_android_sdk_path)
29*c2e18aaaSAndroid Build Coastguard Worker    if jdk_table_xml.config_jdk_table_xml():
30*c2e18aaaSAndroid Build Coastguard Worker        android_sdk_version = jdk_table_xml.android_sdk_version
31*c2e18aaaSAndroid Build Coastguard Worker"""
32*c2e18aaaSAndroid Build Coastguard Worker
33*c2e18aaaSAndroid Build Coastguard Workerfrom __future__ import absolute_import
34*c2e18aaaSAndroid Build Coastguard Worker
35*c2e18aaaSAndroid Build Coastguard Workerimport os
36*c2e18aaaSAndroid Build Coastguard Worker
37*c2e18aaaSAndroid Build Coastguard Workerfrom xml.etree import ElementTree
38*c2e18aaaSAndroid Build Coastguard Worker
39*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen import constant
40*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen import templates
41*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen.lib import aidegen_metrics
42*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen.lib import common_util
43*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen.lib import xml_util
44*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen.sdk import android_sdk
45*c2e18aaaSAndroid Build Coastguard Worker
46*c2e18aaaSAndroid Build Coastguard Worker
47*c2e18aaaSAndroid Build Coastguard Workerclass JDKTableXML:
48*c2e18aaaSAndroid Build Coastguard Worker    """Configs jdk.table.xml for IntelliJ and Android Studio.
49*c2e18aaaSAndroid Build Coastguard Worker
50*c2e18aaaSAndroid Build Coastguard Worker    Attributes:
51*c2e18aaaSAndroid Build Coastguard Worker        _config_file: The absolute file path of the jdk.table.xml, the file
52*c2e18aaaSAndroid Build Coastguard Worker                      might not exist.
53*c2e18aaaSAndroid Build Coastguard Worker        _jdk_content: A string, the content of the JDK configuration.
54*c2e18aaaSAndroid Build Coastguard Worker        _jdk_path: The path of JDK in android project.
55*c2e18aaaSAndroid Build Coastguard Worker        _default_android_sdk_path: The default path to the Android SDK.
56*c2e18aaaSAndroid Build Coastguard Worker        _platform_version: The version name of the platform, e.g. android-29
57*c2e18aaaSAndroid Build Coastguard Worker        _android_sdk_version: The version name of the Android SDK in the
58*c2e18aaaSAndroid Build Coastguard Worker                              jdk.table.xml, e.g. Android API 29 Platform
59*c2e18aaaSAndroid Build Coastguard Worker        _modify_config: A boolean, True to write new content to jdk.table.xml.
60*c2e18aaaSAndroid Build Coastguard Worker        _xml: An xml.etree.ElementTree object contains the XML parsing result.
61*c2e18aaaSAndroid Build Coastguard Worker        _sdk: An AndroidSDK object to get the Android SDK path and platform
62*c2e18aaaSAndroid Build Coastguard Worker              mapping.
63*c2e18aaaSAndroid Build Coastguard Worker    """
64*c2e18aaaSAndroid Build Coastguard Worker    _JDK = 'jdk'
65*c2e18aaaSAndroid Build Coastguard Worker    _NAME = 'name'
66*c2e18aaaSAndroid Build Coastguard Worker    _TYPE = 'type'
67*c2e18aaaSAndroid Build Coastguard Worker    _VALUE = 'value'
68*c2e18aaaSAndroid Build Coastguard Worker    _SDK = 'sdk'
69*c2e18aaaSAndroid Build Coastguard Worker    _HOMEPATH = 'homePath'
70*c2e18aaaSAndroid Build Coastguard Worker    _ADDITIONAL = 'additional'
71*c2e18aaaSAndroid Build Coastguard Worker    _ANDROID_SDK = 'Android SDK'
72*c2e18aaaSAndroid Build Coastguard Worker    _JAVA_SDK = 'JavaSDK'
73*c2e18aaaSAndroid Build Coastguard Worker    _JDK_VERSION = 'JDK21'
74*c2e18aaaSAndroid Build Coastguard Worker    _APPLICATION = 'application'
75*c2e18aaaSAndroid Build Coastguard Worker    _COMPONENT = 'component'
76*c2e18aaaSAndroid Build Coastguard Worker    _PROJECTJDKTABLE = 'ProjectJdkTable'
77*c2e18aaaSAndroid Build Coastguard Worker    _LAST_TAG_TAIL = '\n    '
78*c2e18aaaSAndroid Build Coastguard Worker    _NEW_TAG_TAIL = '\n  '
79*c2e18aaaSAndroid Build Coastguard Worker    _ANDROID_SDK_VERSION = 'Android API {CODE_NAME} Platform'
80*c2e18aaaSAndroid Build Coastguard Worker    _DEFAULT_JDK_TABLE_XML = os.path.join(common_util.get_android_root_dir(),
81*c2e18aaaSAndroid Build Coastguard Worker                                          constant.AIDEGEN_ROOT_PATH,
82*c2e18aaaSAndroid Build Coastguard Worker                                          'data',
83*c2e18aaaSAndroid Build Coastguard Worker                                          'jdk.table.xml')
84*c2e18aaaSAndroid Build Coastguard Worker    _ILLEGAL_XML = ('The {XML} is not an useful XML file for IntelliJ. Do you '
85*c2e18aaaSAndroid Build Coastguard Worker                    'agree AIDEGen override it?(y/n)')
86*c2e18aaaSAndroid Build Coastguard Worker    _IGNORE_XML_WARNING = ('The {XML} is not an useful XML file for IntelliJ. '
87*c2e18aaaSAndroid Build Coastguard Worker                           'It causes the feature "Attach debugger to Android '
88*c2e18aaaSAndroid Build Coastguard Worker                           'process" to be disabled.')
89*c2e18aaaSAndroid Build Coastguard Worker
90*c2e18aaaSAndroid Build Coastguard Worker    def __init__(self, config_file, jdk_content, jdk_path,
91*c2e18aaaSAndroid Build Coastguard Worker                 default_android_sdk_path):
92*c2e18aaaSAndroid Build Coastguard Worker        """JDKTableXML initialize.
93*c2e18aaaSAndroid Build Coastguard Worker
94*c2e18aaaSAndroid Build Coastguard Worker        Args:
95*c2e18aaaSAndroid Build Coastguard Worker            config_file: The absolute file path of the jdk.table.xml, the file
96*c2e18aaaSAndroid Build Coastguard Worker                         might not exist.
97*c2e18aaaSAndroid Build Coastguard Worker            jdk_content: A string, the content of the JDK configuration.
98*c2e18aaaSAndroid Build Coastguard Worker            jdk_path: The path of JDK in android project.
99*c2e18aaaSAndroid Build Coastguard Worker            default_android_sdk_path: The default absolute path to the Android
100*c2e18aaaSAndroid Build Coastguard Worker                                      SDK.
101*c2e18aaaSAndroid Build Coastguard Worker        """
102*c2e18aaaSAndroid Build Coastguard Worker        self._config_file = config_file
103*c2e18aaaSAndroid Build Coastguard Worker        self._jdk_content = jdk_content
104*c2e18aaaSAndroid Build Coastguard Worker        self._jdk_path = jdk_path
105*c2e18aaaSAndroid Build Coastguard Worker        self._default_android_sdk_path = default_android_sdk_path
106*c2e18aaaSAndroid Build Coastguard Worker        self._xml = None
107*c2e18aaaSAndroid Build Coastguard Worker        if os.path.exists(config_file):
108*c2e18aaaSAndroid Build Coastguard Worker            xml_file = config_file
109*c2e18aaaSAndroid Build Coastguard Worker        else:
110*c2e18aaaSAndroid Build Coastguard Worker            xml_file = self._DEFAULT_JDK_TABLE_XML
111*c2e18aaaSAndroid Build Coastguard Worker            common_util.file_generate(xml_file, templates.JDK_TABLE_XML)
112*c2e18aaaSAndroid Build Coastguard Worker        self._xml = xml_util.parse_xml(xml_file)
113*c2e18aaaSAndroid Build Coastguard Worker        self._platform_version = None
114*c2e18aaaSAndroid Build Coastguard Worker        self._android_sdk_version = None
115*c2e18aaaSAndroid Build Coastguard Worker        self._modify_config = False
116*c2e18aaaSAndroid Build Coastguard Worker        self._sdk = android_sdk.AndroidSDK()
117*c2e18aaaSAndroid Build Coastguard Worker
118*c2e18aaaSAndroid Build Coastguard Worker    @property
119*c2e18aaaSAndroid Build Coastguard Worker    def android_sdk_version(self):
120*c2e18aaaSAndroid Build Coastguard Worker        """Gets the Android SDK version."""
121*c2e18aaaSAndroid Build Coastguard Worker        return self._android_sdk_version
122*c2e18aaaSAndroid Build Coastguard Worker
123*c2e18aaaSAndroid Build Coastguard Worker    def _check_structure(self):
124*c2e18aaaSAndroid Build Coastguard Worker        """Checks the XML's structure is correct.
125*c2e18aaaSAndroid Build Coastguard Worker
126*c2e18aaaSAndroid Build Coastguard Worker        The content of the XML file should have a root tag as <application> and
127*c2e18aaaSAndroid Build Coastguard Worker        a child tag <component> of it.
128*c2e18aaaSAndroid Build Coastguard Worker        E.g.
129*c2e18aaaSAndroid Build Coastguard Worker        <application>
130*c2e18aaaSAndroid Build Coastguard Worker          <component name="ProjectJdkTable">
131*c2e18aaaSAndroid Build Coastguard Worker          ...
132*c2e18aaaSAndroid Build Coastguard Worker          </component>
133*c2e18aaaSAndroid Build Coastguard Worker        </application>
134*c2e18aaaSAndroid Build Coastguard Worker
135*c2e18aaaSAndroid Build Coastguard Worker        Returns:
136*c2e18aaaSAndroid Build Coastguard Worker            Boolean: True if the structure is correct, otherwise False.
137*c2e18aaaSAndroid Build Coastguard Worker        """
138*c2e18aaaSAndroid Build Coastguard Worker        if (not self._xml or self._xml.getroot().tag != self._APPLICATION
139*c2e18aaaSAndroid Build Coastguard Worker                or self._xml.find(self._COMPONENT) is None
140*c2e18aaaSAndroid Build Coastguard Worker                or self._xml.find(self._COMPONENT).tag != self._COMPONENT):
141*c2e18aaaSAndroid Build Coastguard Worker            return False
142*c2e18aaaSAndroid Build Coastguard Worker        return self._xml.find(self._COMPONENT).get(
143*c2e18aaaSAndroid Build Coastguard Worker            self._NAME) == self._PROJECTJDKTABLE
144*c2e18aaaSAndroid Build Coastguard Worker
145*c2e18aaaSAndroid Build Coastguard Worker    def _override_xml(self):
146*c2e18aaaSAndroid Build Coastguard Worker        """Overrides the XML file when it's invalid.
147*c2e18aaaSAndroid Build Coastguard Worker
148*c2e18aaaSAndroid Build Coastguard Worker        Returns:
149*c2e18aaaSAndroid Build Coastguard Worker            A boolean, True when developers choose to override the XML file,
150*c2e18aaaSAndroid Build Coastguard Worker            otherwise False.
151*c2e18aaaSAndroid Build Coastguard Worker        """
152*c2e18aaaSAndroid Build Coastguard Worker        input_data = input(self._ILLEGAL_XML.format(XML=self._config_file))
153*c2e18aaaSAndroid Build Coastguard Worker        while input_data not in ('y', 'n'):
154*c2e18aaaSAndroid Build Coastguard Worker            input_data = input('Please type y(Yes) or n(No): ')
155*c2e18aaaSAndroid Build Coastguard Worker        if input_data == 'y':
156*c2e18aaaSAndroid Build Coastguard Worker            # Record the exception about wrong XML format.
157*c2e18aaaSAndroid Build Coastguard Worker            if self._xml:
158*c2e18aaaSAndroid Build Coastguard Worker                aidegen_metrics.send_exception_metrics(
159*c2e18aaaSAndroid Build Coastguard Worker                    constant.XML_PARSING_FAILURE, '',
160*c2e18aaaSAndroid Build Coastguard Worker                    ElementTree.tostring(self._xml.getroot()), '')
161*c2e18aaaSAndroid Build Coastguard Worker            self._xml = xml_util.parse_xml(self._DEFAULT_JDK_TABLE_XML)
162*c2e18aaaSAndroid Build Coastguard Worker            return True
163*c2e18aaaSAndroid Build Coastguard Worker        return False
164*c2e18aaaSAndroid Build Coastguard Worker
165*c2e18aaaSAndroid Build Coastguard Worker    def _check_jdk21_in_xml(self):
166*c2e18aaaSAndroid Build Coastguard Worker        """Checks if the JDK21 is already set in jdk.table.xml.
167*c2e18aaaSAndroid Build Coastguard Worker
168*c2e18aaaSAndroid Build Coastguard Worker        Returns:
169*c2e18aaaSAndroid Build Coastguard Worker            Boolean: True if the JDK21 exists else False.
170*c2e18aaaSAndroid Build Coastguard Worker        """
171*c2e18aaaSAndroid Build Coastguard Worker        for jdk in self._xml.iter(self._JDK):
172*c2e18aaaSAndroid Build Coastguard Worker            _name = jdk.find(self._NAME)
173*c2e18aaaSAndroid Build Coastguard Worker            _type = jdk.find(self._TYPE)
174*c2e18aaaSAndroid Build Coastguard Worker            if None in (_name, _type):
175*c2e18aaaSAndroid Build Coastguard Worker                continue
176*c2e18aaaSAndroid Build Coastguard Worker            if (_type.get(self._VALUE) == self._JAVA_SDK
177*c2e18aaaSAndroid Build Coastguard Worker                    and _name.get(self._VALUE) == self._JDK_VERSION):
178*c2e18aaaSAndroid Build Coastguard Worker                return True
179*c2e18aaaSAndroid Build Coastguard Worker        return False
180*c2e18aaaSAndroid Build Coastguard Worker
181*c2e18aaaSAndroid Build Coastguard Worker    def _check_android_sdk_in_xml(self):
182*c2e18aaaSAndroid Build Coastguard Worker        """Checks if the Android SDK is already set in jdk.table.xml.
183*c2e18aaaSAndroid Build Coastguard Worker
184*c2e18aaaSAndroid Build Coastguard Worker        If the Android SDK exists in xml, validate the value of Android SDK path
185*c2e18aaaSAndroid Build Coastguard Worker        and platform version.
186*c2e18aaaSAndroid Build Coastguard Worker        1. Check if the Android SDK path is valid.
187*c2e18aaaSAndroid Build Coastguard Worker        2. Check if the platform version exists in the Android SDK.
188*c2e18aaaSAndroid Build Coastguard Worker        The Android SDK version can be used to generate enable_debugger module
189*c2e18aaaSAndroid Build Coastguard Worker        when condition 1 and 2 are true.
190*c2e18aaaSAndroid Build Coastguard Worker
191*c2e18aaaSAndroid Build Coastguard Worker        Returns:
192*c2e18aaaSAndroid Build Coastguard Worker            Boolean: True if the Android SDK configuration exists, otherwise
193*c2e18aaaSAndroid Build Coastguard Worker                     False.
194*c2e18aaaSAndroid Build Coastguard Worker        """
195*c2e18aaaSAndroid Build Coastguard Worker        for tag in self._xml.iter(self._JDK):
196*c2e18aaaSAndroid Build Coastguard Worker            _name = tag.find(self._NAME)
197*c2e18aaaSAndroid Build Coastguard Worker            _type = tag.find(self._TYPE)
198*c2e18aaaSAndroid Build Coastguard Worker            _homepath = tag.find(self._HOMEPATH)
199*c2e18aaaSAndroid Build Coastguard Worker            _additional = tag.find(self._ADDITIONAL)
200*c2e18aaaSAndroid Build Coastguard Worker            if None in (_name, _type, _homepath, _additional):
201*c2e18aaaSAndroid Build Coastguard Worker                continue
202*c2e18aaaSAndroid Build Coastguard Worker
203*c2e18aaaSAndroid Build Coastguard Worker            tag_type = _type.get(self._VALUE)
204*c2e18aaaSAndroid Build Coastguard Worker            home_path = _homepath.get(self._VALUE).replace(
205*c2e18aaaSAndroid Build Coastguard Worker                constant.USER_HOME, os.path.expanduser('~'))
206*c2e18aaaSAndroid Build Coastguard Worker            platform = _additional.get(self._SDK)
207*c2e18aaaSAndroid Build Coastguard Worker            if (tag_type != self._ANDROID_SDK
208*c2e18aaaSAndroid Build Coastguard Worker                    or not self._sdk.is_android_sdk_path(home_path)
209*c2e18aaaSAndroid Build Coastguard Worker                    or platform not in self._sdk.platform_mapping):
210*c2e18aaaSAndroid Build Coastguard Worker                continue
211*c2e18aaaSAndroid Build Coastguard Worker            self._android_sdk_version = _name.get(self._VALUE)
212*c2e18aaaSAndroid Build Coastguard Worker            self._platform_version = platform
213*c2e18aaaSAndroid Build Coastguard Worker            return True
214*c2e18aaaSAndroid Build Coastguard Worker        return False
215*c2e18aaaSAndroid Build Coastguard Worker
216*c2e18aaaSAndroid Build Coastguard Worker    def _append_config(self, new_config):
217*c2e18aaaSAndroid Build Coastguard Worker        """Adds a <jdk> configuration at the last of <component>.
218*c2e18aaaSAndroid Build Coastguard Worker
219*c2e18aaaSAndroid Build Coastguard Worker        Args:
220*c2e18aaaSAndroid Build Coastguard Worker            new_config: A string of new <jdk> configuration.
221*c2e18aaaSAndroid Build Coastguard Worker        """
222*c2e18aaaSAndroid Build Coastguard Worker        node = ElementTree.fromstring(new_config)
223*c2e18aaaSAndroid Build Coastguard Worker        node.tail = self._NEW_TAG_TAIL
224*c2e18aaaSAndroid Build Coastguard Worker        component = self._xml.getroot().find(self._COMPONENT)
225*c2e18aaaSAndroid Build Coastguard Worker        if len(component) > 0:
226*c2e18aaaSAndroid Build Coastguard Worker            component[-1].tail = self._LAST_TAG_TAIL
227*c2e18aaaSAndroid Build Coastguard Worker        else:
228*c2e18aaaSAndroid Build Coastguard Worker            component.text = self._LAST_TAG_TAIL
229*c2e18aaaSAndroid Build Coastguard Worker        self._xml.getroot().find(self._COMPONENT).append(node)
230*c2e18aaaSAndroid Build Coastguard Worker
231*c2e18aaaSAndroid Build Coastguard Worker    def _generate_jdk_config_string(self):
232*c2e18aaaSAndroid Build Coastguard Worker        """Generates the default JDK configuration."""
233*c2e18aaaSAndroid Build Coastguard Worker        if self._check_jdk21_in_xml():
234*c2e18aaaSAndroid Build Coastguard Worker            return
235*c2e18aaaSAndroid Build Coastguard Worker        self._append_config(self._jdk_content.format(JDKpath=self._jdk_path))
236*c2e18aaaSAndroid Build Coastguard Worker        self._modify_config = True
237*c2e18aaaSAndroid Build Coastguard Worker
238*c2e18aaaSAndroid Build Coastguard Worker    def _generate_sdk_config_string(self):
239*c2e18aaaSAndroid Build Coastguard Worker        """Generates Android SDK configuration."""
240*c2e18aaaSAndroid Build Coastguard Worker        if self._check_android_sdk_in_xml():
241*c2e18aaaSAndroid Build Coastguard Worker            return
242*c2e18aaaSAndroid Build Coastguard Worker        if self._sdk.path_analysis(self._default_android_sdk_path):
243*c2e18aaaSAndroid Build Coastguard Worker            # TODO(b/151582629): Revise the API_LEVEL to CODE_NAME when
244*c2e18aaaSAndroid Build Coastguard Worker            #                    abandoning the sdk_config.py.
245*c2e18aaaSAndroid Build Coastguard Worker            self._append_config(templates.ANDROID_SDK_XML.format(
246*c2e18aaaSAndroid Build Coastguard Worker                ANDROID_SDK_PATH=self._sdk.android_sdk_path,
247*c2e18aaaSAndroid Build Coastguard Worker                FOLDER_NAME=self._sdk.max_folder_name,
248*c2e18aaaSAndroid Build Coastguard Worker                CODE_NAME=self._sdk.max_code_name))
249*c2e18aaaSAndroid Build Coastguard Worker            self._android_sdk_version = self._ANDROID_SDK_VERSION.format(
250*c2e18aaaSAndroid Build Coastguard Worker                CODE_NAME=self._sdk.max_code_name)
251*c2e18aaaSAndroid Build Coastguard Worker            self._modify_config = True
252*c2e18aaaSAndroid Build Coastguard Worker            return
253*c2e18aaaSAndroid Build Coastguard Worker        # Record the exception about missing Android SDK.
254*c2e18aaaSAndroid Build Coastguard Worker        aidegen_metrics.send_exception_metrics(
255*c2e18aaaSAndroid Build Coastguard Worker            constant.LOCATE_SDK_PATH_FAILURE, '',
256*c2e18aaaSAndroid Build Coastguard Worker            ElementTree.tostring(self._xml.getroot()), '')
257*c2e18aaaSAndroid Build Coastguard Worker
258*c2e18aaaSAndroid Build Coastguard Worker    def config_jdk_table_xml(self):
259*c2e18aaaSAndroid Build Coastguard Worker        """Configures the jdk.table.xml.
260*c2e18aaaSAndroid Build Coastguard Worker
261*c2e18aaaSAndroid Build Coastguard Worker        1. Generate the JDK21 configuration if it does not exist.
262*c2e18aaaSAndroid Build Coastguard Worker        2. Generate the Android SDK configuration if it does not exist and
263*c2e18aaaSAndroid Build Coastguard Worker           save the Android SDK path.
264*c2e18aaaSAndroid Build Coastguard Worker        3. Update the jdk.table.xml if AIDEGen needs to append JDK21 or
265*c2e18aaaSAndroid Build Coastguard Worker           Android SDK configuration.
266*c2e18aaaSAndroid Build Coastguard Worker
267*c2e18aaaSAndroid Build Coastguard Worker        Returns:
268*c2e18aaaSAndroid Build Coastguard Worker            A boolean, True when get the Android SDK version, otherwise False.
269*c2e18aaaSAndroid Build Coastguard Worker        """
270*c2e18aaaSAndroid Build Coastguard Worker        if not self._check_structure() and not self._override_xml():
271*c2e18aaaSAndroid Build Coastguard Worker            print(self._IGNORE_XML_WARNING.format(XML=self._config_file))
272*c2e18aaaSAndroid Build Coastguard Worker            return False
273*c2e18aaaSAndroid Build Coastguard Worker        self._generate_jdk_config_string()
274*c2e18aaaSAndroid Build Coastguard Worker        self._generate_sdk_config_string()
275*c2e18aaaSAndroid Build Coastguard Worker        if self._modify_config:
276*c2e18aaaSAndroid Build Coastguard Worker            if not os.path.exists(self._config_file):
277*c2e18aaaSAndroid Build Coastguard Worker                common_util.file_generate(
278*c2e18aaaSAndroid Build Coastguard Worker                    self._config_file, templates.JDK_TABLE_XML)
279*c2e18aaaSAndroid Build Coastguard Worker            self._xml.write(self._config_file)
280*c2e18aaaSAndroid Build Coastguard Worker        return bool(self._android_sdk_version)
281