xref: /aosp_15_r20/external/bazelbuild-rules_android/mobile_install/launcher_direct.bzl (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
1# Copyright 2018 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Creates the app launcher scripts."""
15
16load(":utils.bzl", "utils")
17load(":workspace.bzl", "make_dex_sync", "make_generic_sync", "merge_syncs")
18load(":deploy_info.bzl", "make_deploy_info_pb")
19load(":providers.bzl", "MIAppInfo", "MIAppLaunchInfo")
20load("//rules/flags:flags.bzl", "flags")
21
22HOST_TEST_WORKSPACE = "host_test_runner_workspace"
23
24_DEPLOY_SCRIPT = '''#!/bin/bash
25set -e  # exit on failure
26umask 022  # set default file/dir creation mode to 755
27
28FLAGS={flags}
29TEST_FLAGS={test_flags}
30DEPLOY={deploy}
31
32
33ALL_TEST_ARGS=("$@")
34if [[ ! -z ${{TEST_FLAGS}} ]];
35then
36  RULE_TEST_ARGS={test_args}
37  ALL_TEST_ARGS=("--nolaunch_app" "${{RULE_TEST_ARGS[@]}}" "$@")
38  "${{DEPLOY}}" \
39      -flagfile="${{TEST_FLAGS}}"  \
40      "${{ALL_TEST_ARGS[@]}}"
41else
42    "${{DEPLOY}}" -flagfile="${{FLAGS}}" \
43      "${{ALL_TEST_ARGS[@]}}"
44fi
45
46'''
47
48def _make_deploy_script(
49        ctx,
50        out_script,
51        deploy,
52        flags,
53        test_args = "",
54        test_flags = ""):
55    deploy_contents = _DEPLOY_SCRIPT.format(
56        deploy = deploy,
57        flags = flags,
58        test_flags = test_flags,
59        test_args = test_args,
60    )
61    ctx.actions.write(out_script, deploy_contents, is_executable = True)
62
63def _make_app_runner(
64        ctx,
65        sync,
66        manifest_package_name_path,
67        out_launcher,
68        out_launcher_flags,
69        shell_apk = None,
70        splits = None,
71        deploy_info_pb = None,
72        test_apk = None,
73        test_data = None,
74        test_args = None,
75        instrumented_app_package_name = None,
76        use_adb_root = True,
77        enable_metrics_logging = False,
78        use_studio_deployer = True,
79        is_test = False):
80    path_type = "path" if ctx.attr._mi_is_cmd else "short_path"
81
82    deploy = utils.first(ctx.attr._deploy.files.to_list())
83
84    args = {
85        "data_sync_path": getattr(sync, path_type),
86        "is_cmd": str(ctx.attr._mi_is_cmd).lower(),
87        "manifest_package_name_path": getattr(manifest_package_name_path, path_type),
88        "target": ctx.label,
89    }
90    if shell_apk:
91        args["shell_app_path"] = getattr(shell_apk, path_type)
92
93    if splits:
94        args["splits"] = [getattr(s, path_type) for s in splits]
95        args["enable_splits"] = True
96
97    if ctx.attr._mi_is_cmd:
98        args["host_test_runner_workspace"] = HOST_TEST_WORKSPACE
99
100    args["java_home"] = utils.host_jvm_path(ctx)
101
102    args["studio_deployer"] = getattr(ctx.file._studio_deployer, path_type)
103    args["use_adb_root"] = str(use_adb_root).lower()
104    args["enable_metrics_logging"] = str(enable_metrics_logging).lower()
105    args["use_studio_deployer"] = str(use_studio_deployer).lower()
106
107    args["use_direct_deploy"] = True
108
109    android_test_runner = None
110    if is_test and hasattr(ctx.attr, "_android_test_runner"):
111        android_test_runner = ctx.file._android_test_runner
112        args["android_test_runner"] = getattr(android_test_runner, path_type)
113        args["is_test"] = True
114
115    if test_data:
116        args["data_files"] = ",".join([f.short_path for f in test_data])
117
118    if test_apk:
119        args["test_apk"] = test_apk.path
120
121    if instrumented_app_package_name:
122        args["instrumented_app_package_name"] = getattr(instrumented_app_package_name, path_type)
123
124    if deploy_info_pb:
125        args["deploy_info"] = getattr(deploy_info_pb, path_type)
126
127    utils.create_flag_file(ctx, out_launcher_flags, **args)
128
129    _make_deploy_script(
130        ctx,
131        out_launcher,
132        getattr(deploy, path_type),
133        flags = getattr(out_launcher_flags, path_type),
134        # Converts the python array of args into a bash array. Each arg is
135        # wrapped with quotes to handle "space" separted flag value entries
136        # and as result also escapes existing quotes.
137        test_args = ("(%s)" % " ".join([
138            '"--test_arg=%s"' % arg.replace('"', '\\"')
139            for arg in test_args
140        ])) if test_args else "",
141        test_flags = getattr(out_launcher_flags, path_type) if test_args or is_test else "",
142    )
143
144    runner = [deploy]
145    if android_test_runner:
146        runner.extend(ctx.attr._java_jdk.files.to_list())
147        runner.append(android_test_runner)
148    return runner
149
150def make_direct_launcher(
151        ctx,
152        mi_app_info,
153        launcher,
154        test_data = None,
155        test_args = None,
156        test_support_apps = None,
157        use_adb_root = True,
158        is_test = False):
159    """ Runfiles for launching the apps are created.
160
161    Args:
162        ctx: The context
163        mi_app_info: The MIAppInfo provider
164        launcher: The launcher file
165        test_data: The test data
166        test_support_apps: The test support apps
167        test_args: The test arguments
168        use_adb_root: Boolean argument to restart adb with root permissions.
169        is_test: Boolean argument to identify if it's a test
170    Returns:
171        A list of files required for runtime common for both running binary and test.
172    """
173    app_pbs = []
174    runfiles = []
175
176    launcher_flags = utils.isolated_declare_file(ctx, "launcher.flag", sibling = launcher)
177
178    runfiles.extend([launcher, launcher_flags])
179
180    runfiles.append(ctx.file._studio_deployer)
181    if getattr(mi_app_info, "merged_manifest", None):
182        runfiles.append(mi_app_info.merged_manifest)
183    runfiles.append(mi_app_info.manifest_package_name)
184
185    shell_apk = None
186    if hasattr(mi_app_info, "shell_apk") and mi_app_info.shell_apk:
187        shell_apk = mi_app_info.shell_apk
188        app_pbs.append(
189            make_generic_sync(
190                ctx,
191                files = [shell_apk],
192                replacements = [
193                    shell_apk.short_path[:shell_apk.short_path.rindex("/")],
194                    "apk",
195                ],
196                sibling = launcher,
197            ),
198        )
199        runfiles.append(mi_app_info.shell_apk)
200
201    splits = None
202    if hasattr(mi_app_info, "splits"):
203        splits = mi_app_info.splits
204        runfiles.extend(mi_app_info.splits)
205
206    if hasattr(mi_app_info, "native_zip") and mi_app_info.native_zip:
207        app_pbs.append(make_generic_sync(ctx, zips = [mi_app_info.native_zip], sibling = launcher))
208        runfiles.append(mi_app_info.native_zip)
209
210    if hasattr(mi_app_info, "r_dex"):
211        runfiles.append(mi_app_info.r_dex)
212        app_pbs.append(make_dex_sync(ctx, mi_app_info.r_dex, dir_name = "rdexes", sibling = launcher))
213
214    if hasattr(mi_app_info, "merged_dex_shards"):
215        runfiles.extend(mi_app_info.merged_dex_shards)
216        bin_dex_sync = merge_syncs(
217            ctx,
218            [
219                make_dex_sync(ctx, dex_shard, sibling = launcher)
220                for dex_shard in mi_app_info.merged_dex_shards
221            ],
222            "bin",
223            sibling = launcher,
224        )
225        app_pbs.append(bin_dex_sync)
226
227    deploy_info_pb = None
228    if hasattr(mi_app_info, "merged_manifest"):
229        deploy_info_pb = make_deploy_info_pb(
230            ctx,
231            mi_app_info.merged_manifest,
232            mi_app_info.splits if mi_app_info.splits else [mi_app_info.shell_apk],
233        )
234        runfiles.append(deploy_info_pb)
235
236    if test_data:
237        runfiles.extend(test_data)
238    if is_test:
239        test_apk = mi_app_info.apk
240        runfiles.append(test_apk)
241    else:
242        test_apk = None
243
244    sync = utils.make_sync(ctx, app_pbs, mi_app_info.manifest_package_name, "app", sibling = launcher)
245    runfiles.append(sync)
246
247    sync_pbs = []
248    sync_pbs.append(sync)
249    instrumented_app_package_name = None
250    instrumented_app = None
251    if hasattr(mi_app_info, "instrumented_app") and mi_app_info.instrumented_app:
252        sync_pbs.append(mi_app_info.instrumented_app[MIAppLaunchInfo].sync)
253        runfiles.extend(mi_app_info.instrumented_app[MIAppLaunchInfo].runfiles)
254        instrumented_app_package_name = mi_app_info.instrumented_app[MIAppInfo].manifest_package_name
255
256    if test_support_apps:
257        for support_app in test_support_apps:
258            if MIAppLaunchInfo in support_app:
259                sync_pbs.append(support_app[MIAppLaunchInfo].sync)
260                runfiles.extend(support_app[MIAppLaunchInfo].runfiles)
261
262    if len(sync_pbs) > 1:
263        final_sync_pb = utils.sync_merger(ctx, sync_pbs, sibling = launcher)
264        runfiles.append(final_sync_pb)
265    else:
266        final_sync_pb = sync
267
268    runfiles.extend(_make_app_runner(
269        ctx,
270        final_sync_pb,
271        mi_app_info.manifest_package_name,
272        launcher,
273        launcher_flags,
274        shell_apk = shell_apk,
275        splits = splits,
276        deploy_info_pb = deploy_info_pb,
277        test_apk = test_apk,
278        test_data = test_data,
279        test_args = test_args,
280        instrumented_app_package_name = instrumented_app_package_name,
281        use_adb_root = use_adb_root,
282        enable_metrics_logging = flags.get(ctx).enable_metrics_logging,
283        use_studio_deployer = flags.get(ctx).use_studio_deployer,
284        is_test = is_test,
285    ))
286
287    return MIAppLaunchInfo(
288        launcher = launcher,
289        launcher_flags = launcher_flags,
290        runfiles = runfiles,
291        sync = sync,
292    )
293