• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/system/bin/sh
2
3#
4# Copyright (C) 2016 The Android Open Source Project
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#      http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19# This script runs as a postinstall step to drive otapreopt. It comes with the
20# OTA package, but runs /system/bin/otapreopt_chroot in the (old) active system
21# image. See system/extras/postinst/postinst.sh for some docs.
22
23TARGET_SLOT="$1"
24STATUS_FD="$2"
25
26# "1" if the script is triggered by the `UpdateEngine.triggerPostinstall` API. Empty otherwise.
27TRIGGERED_BY_API="$3"
28
29# Maximum number of packages/steps.
30MAXIMUM_PACKAGES=1000
31
32# First ensure the system is booted. This is to work around issues when cmd would
33# infinitely loop trying to get a service manager (which will never come up in that
34# mode). b/30797145
35BOOT_PROPERTY_NAME="dev.bootcomplete"
36
37BOOT_COMPLETE=$(getprop $BOOT_PROPERTY_NAME)
38if [ "$BOOT_COMPLETE" != "1" ] ; then
39  echo "$0: Error: boot-complete not detected."
40  # We must return 0 to not block sideload.
41  exit 0
42fi
43
44# Compute target slot suffix.
45# TODO: Once bootctl is not restricted, we should query from there. Or get this from
46#       update_engine as a parameter.
47if [ "$TARGET_SLOT" = "0" ] ; then
48  TARGET_SLOT_SUFFIX="_a"
49elif [ "$TARGET_SLOT" = "1" ] ; then
50  TARGET_SLOT_SUFFIX="_b"
51else
52  echo "$0: Unknown target slot $TARGET_SLOT"
53  exit 1
54fi
55
56# A source that infinitely emits arbitrary lines.
57# When connected to STDIN of another process, this source keeps STDIN open until
58# the consumer process closes STDIN or this script dies.
59# In practice, the pm command keeps consuming STDIN, so we don't need to worry
60# about running out of buffer space.
61function infinite_source {
62  while echo .; do
63    sleep 1
64  done
65}
66
67if [[ "$TRIGGERED_BY_API" = "1" ]]; then
68  # During OTA installation, the script is called the first time, and
69  # `TRIGGERED_BY_API` can never be "1". `TRIGGERED_BY_API` being "1" means this
70  # is the second call to this script, through the
71  # `UpdateEngine.triggerPostinstall` API.
72  # When we reach here, it means Pre-reboot Dexopt is enabled in asynchronous
73  # mode and the job scheduler determined that it's the time to run the job.
74  # Start Pre-reboot Dexopt now and wait for it to finish.
75  infinite_source | pm art on-ota-staged --start
76  exit $?
77fi
78
79PR_DEXOPT_JOB_VERSION="$(pm art pr-dexopt-job --version)"
80if (( $? == 0 )) && (( $PR_DEXOPT_JOB_VERSION >= 3 )); then
81  # Delegate to Pre-reboot Dexopt, a feature of ART Service.
82  # ART Service decides what to do with this request:
83  # - If Pre-reboot Dexopt is disabled or unsupported, the command returns
84  #   non-zero.
85  #   This is always the case if the current system is Android 14 or earlier.
86  # - If Pre-reboot Dexopt is enabled in synchronous mode, the command blocks
87  #   until Pre-reboot Dexopt finishes, and returns zero no matter it succeeds
88  #   or not.
89  #   This is the default behavior if the current system is Android 15.
90  # - If Pre-reboot Dexopt is enabled in asynchronous mode, the command
91  #   schedules an asynchronous job and returns 0 immediately.
92  #   Later, when the device is idle and charging, the job will be run by the
93  #   job scheduler. It will call this script again through the
94  #   `UpdateEngine.triggerPostinstall` API, with `TRIGGERED_BY_API` being "1".
95  #   This is always the case if the current system is Android 16 or later.
96  if infinite_source | pm art on-ota-staged --slot "$TARGET_SLOT_SUFFIX"; then
97    # Handled by Pre-reboot Dexopt.
98    exit 0
99  fi
100  echo "Pre-reboot Dexopt not enabled. Fall back to otapreopt."
101else
102  echo "Pre-reboot Dexopt is too old. Fall back to otapreopt."
103fi
104
105if [ "$(/system/bin/otapreopt_chroot --version)" != 2 ]; then
106  # We require an updated chroot wrapper that reads dexopt commands from stdin.
107  # Even if we kept compat with the old binary, the OTA preopt wouldn't work due
108  # to missing sepolicy rules, so there's no use spending time trying to dexopt
109  # (b/291974157).
110  echo "$0: Current system image is too old to work with OTA preopt - skipping."
111  exit 0
112fi
113
114PREPARE=$(cmd otadexopt prepare)
115# Note: Ignore preparation failures. Step and done will fail and exit this.
116#       This is necessary to support suspends - the OTA service will keep
117#       the state around for us.
118
119# Create an array with all dexopt commands in advance, to know how many there are.
120otadexopt_cmds=()
121while (( ${#otadexopt_cmds[@]} < MAXIMUM_PACKAGES )) ; do
122  DONE=$(cmd otadexopt done)
123  if [ "$DONE" = "OTA complete." ] ; then
124    break
125  fi
126  otadexopt_cmds+=("$(cmd otadexopt next)")
127done
128
129DONE=$(cmd otadexopt done)
130cmd otadexopt cleanup
131
132echo "$0: Using streaming otapreopt_chroot on ${#otadexopt_cmds[@]} packages"
133
134function print_otadexopt_cmds {
135  for cmd in "${otadexopt_cmds[@]}" ; do
136    print "$cmd"
137  done
138}
139
140function report_progress {
141  while read count ; do
142    # mksh can't do floating point arithmetic, so emulate a fixed point calculation.
143    (( permilles = 1000 * count / ${#otadexopt_cmds[@]} ))
144    printf 'global_progress %d.%03d\n' $((permilles / 1000)) $((permilles % 1000)) >&${STATUS_FD}
145  done
146}
147
148print_otadexopt_cmds | \
149  /system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX | \
150  report_progress
151
152if [ "$DONE" = "OTA incomplete." ] ; then
153  echo "$0: Incomplete."
154else
155  echo "$0: Complete or error."
156fi
157
158print -u${STATUS_FD} "global_progress 1.0"
159
160exit 0
161