name: OpenHarmony on: workflow_call: inputs: profile: required: false default: "release" type: string upload: required: false default: false type: boolean github-release-id: required: false type: string bencher: required: false default: false type: boolean workflow_dispatch: inputs: profile: required: false default: "release" type: choice description: "Cargo build profile" options: ["release", "debug", "production"] bencher: required: false default: false type: boolean env: RUST_BACKTRACE: 1 SHELL: /bin/bash CARGO_INCREMENTAL: 0 BENCHER_PROJECT: ${{ vars.BENCHER_PROJECT || 'servo' }} HITRACE_BENCH_VERSION: 0.8.2 jobs: build: name: OpenHarmony Build runs-on: ubuntu-22.04 strategy: matrix: target: ["aarch64-unknown-linux-ohos", "x86_64-unknown-linux-ohos"] outputs: signed: ${{ steps.signing_config.outputs.signed }} steps: - uses: actions/checkout@v4 if: github.event_name != 'pull_request_target' with: fetch-depth: 2 # This is necessary to checkout the pull request if this run was triggered via a # `pull_request_target` event. - uses: actions/checkout@v4 if: github.event_name == 'pull_request_target' with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 2 - name: Install crown run: cargo install --path support/crown - name: Setup Python uses: ./.github/actions/setup-python - name: Bootstrap dependencies run: sudo apt update && ./mach bootstrap --skip-lints - name: Setup OpenHarmony SDK id: setup_sdk uses: openharmony-rs/setup-ohos-sdk@v0.2.3 with: version: "5.0.2" fixup-path: true - name: Install node for hvigor uses: actions/setup-node@v4 with: node-version: 18 - name: Install hvigor modules run: | mkdir ~/hvigor-installation cd ~/hvigor-installation echo "@ohos:registry=https://repo.harmonyos.com/npm/" > .npmrc npm install "@ohos/hvigor@5" "@ohos/hvigor-ohos-plugin@5" echo "HVIGOR_PATH=$PWD" >> $GITHUB_ENV - name: "Setup HAP signing config" id: signing_config env: SIGNING_MATERIAL: ${{ secrets.SERVO_OHOS_SIGNING_MATERIAL }} if: ${{ inputs.upload || env.SIGNING_MATERIAL != '' }} # Allows the build to pass on forks. run: | cd ~ echo "${SIGNING_MATERIAL}" | base64 -d > servo-ohos-material.zip unzip servo-ohos-material.zip echo "SERVO_OHOS_SIGNING_CONFIG=${PWD}/servo-ohos-material/signing-configs.json" >> $GITHUB_ENV echo "signed=true" >> "$GITHUB_OUTPUT" - name: Build (arch ${{ matrix.target }} profile ${{ inputs.profile }}) env: OHOS_SDK_NATIVE: ${{ steps.setup_sdk.outputs.ohos_sdk_native }} OHOS_BASE_SDK_HOME: ${{ steps.setup_sdk.outputs.ohos-base-sdk-home }} run: | ./mach build --locked --target ${{ matrix.target }} --${{ inputs.profile }} cp -r target/cargo-timings target/cargo-timings-ohos-${{ matrix.target }} - name: Archive build timing uses: actions/upload-artifact@v4 with: name: cargo-timings-ohos-${{ matrix.target }}-${{ inputs.profile }} # Using a wildcard here ensures that the archive includes the path. path: target/cargo-timings-* - name: Upload nightly if: ${{ inputs.upload && contains(matrix.target, 'aarch64') }} run: | ./mach upload-nightly ohos \ --secret-from-environment \ --github-release-id ${{ inputs.github-release-id }} env: S3_UPLOAD_CREDENTIALS: ${{ secrets.S3_UPLOAD_CREDENTIALS }} NIGHTLY_REPO_TOKEN: ${{ secrets.NIGHTLY_REPO_TOKEN }} NIGHTLY_REPO: ${{ github.repository_owner }}/servo-nightly-builds - name: Generate artifact attestation for HAP if: ${{ inputs.upload }} uses: actions/attest-build-provenance@v1 with: subject-path: target/openharmony/${{ matrix.target }}/${{ inputs.profile }}/entry/build/default/outputs/default/servoshell-default-signed.hap - name: Upload signed HAP artifact if: ${{ env.SERVO_OHOS_SIGNING_CONFIG != '' }} # Build output has different name if not signed. uses: actions/upload-artifact@v4 with: name: ${{ inputs.profile }}-binary-ohos-${{ matrix.target }} path: target/openharmony/${{ matrix.target }}/${{ inputs.profile }}/entry/build/default/outputs/default/servoshell-default-signed.hap - name: Upload unsigned HAP artifact if: ${{ env.SERVO_OHOS_SIGNING_CONFIG == '' }} # Build output has different name if not signed. uses: actions/upload-artifact@v4 with: name: ${{ inputs.profile }}-binary-ohos-${{ matrix.target }} path: target/openharmony/${{ matrix.target }}/${{ inputs.profile }}/entry/build/default/outputs/default/servoshell-default-unsigned.hap bencher: needs: ["build"] strategy: matrix: target: ["aarch64-unknown-linux-ohos", "x86_64-unknown-linux-ohos"] if: ${{ inputs.bencher && inputs.profile != 'debug' && github.event_name != 'workflow_dispatch' && github.event_name != 'merge_group' }} uses: ./.github/workflows/bencher.yml with: target: ohos-${{ matrix.target }} profile: ${{ inputs.profile }} compressed-file-path: ${{ inputs.profile }}-binary-ohos-${{ matrix.target }}/servoshell-default-${{ needs.build.outputs.signed && 'signed' || 'unsigned' }}.hap binary-path: libs/${{ matrix.target == 'aarch64-unknown-linux-ohos' && 'arm64-v8a' || matrix.target == 'x86_64-unknown-linux-ohos' && 'x86_64' }}/libservoshell.so file-size: true speedometer: false dromaeo: false secrets: inherit # Note: We could potentially also merge this build job with the above one, # if we figure out how to make hvigor build for harmonyos without the HOS commandline-tools installed. build-harmonyos-aarch64: name: HarmonyOS Build (aarch64) continue-on-error: true runs-on: hos-builder if: github.repository == 'servo/servo' steps: - if: ${{ github.event_name != 'pull_request_target' }} run: git fetch --depth=1 origin $GITHUB_SHA - if: ${{ github.event_name == 'pull_request_target' }} run: git fetch --depth=1 origin ${{ github.event.pull_request.head.sha }} - run: | git switch --detach git reset --hard FETCH_HEAD - name: Adding test files to directory run: cp -r support/hitrace-bencher/* support/openharmony/AppScope/resources/resfile/ - name: Build for aarch64 HarmonyOS run: | ./mach build --locked --target aarch64-unknown-linux-ohos --profile=${{ inputs.profile }} --flavor=harmonyos --no-default-features --features tracing,tracing-hitrace - uses: actions/upload-artifact@v4 with: # Upload the **unsigned** artifact - We don't have the signing materials in pull request workflows name: servoshell-hos-${{ inputs.profile }}.hap path: target/openharmony/aarch64-unknown-linux-ohos/${{ inputs.profile }}/entry/build/harmonyos/outputs/default/servoshell-default-unsigned.hap test-harmonyos-aarch64: name: Test HarmonyOS aarch64 # Don't block servos Merge queue on this job failing. # Since we just added this, there might be some hidden issues, # so in the beginning we will just do a best effort approach but ignore errors. continue-on-error: true runs-on: hos-runner if: github.repository == 'servo/servo' needs: build-harmonyos-aarch64 steps: - uses: actions/download-artifact@v4 with: # Name of the artifact to download. # If unspecified, all artifacts for the run are downloaded. name: servoshell-hos-${{ inputs.profile }}.hap - name: Test hdc device # First we ensure a device is actually connected and working. run: hdc list targets && hdc shell echo hello world - name: Sign the hap run: | ls -la /usr/bin/sign-hos.sh servoshell-default-unsigned.hap servoshell-hos-signed.hap - name: Install run: | # Uninstall first. hdc is not very reliable in terms of exiting with an error, so we uninstall first # to make sure we don't use a previous version if installation failed for some reason. hdc uninstall org.servo.servo hdc install -r servoshell-hos-signed.hap - name: Test loading servo.org env: TRACE_BUFFER_SZ_KB: "524288" # 512 MB run: | mkdir test_output hdc shell aa force-stop org.servo.servo # Hitrace allows us to save application and system traces, which is useful to analyze performance. # The main reason however, is that we can use the application traces to determine if servo # successfully reaches certain locations in the code, in particular if a page is successfully loaded. hdc shell hitrace -b "${TRACE_BUFFER_SZ_KB}" app graphic ohos freq idle memory --trace_begin # We start servo, tell it to load a website (servo.org). JIT is not allowed on HarmonyOS 5. hdc shell aa start -a EntryAbility -b org.servo.servo -U https://servo.org --ps=--pref js_disable_jit=true servo_pid=$(hdc shell pidof org.servo.servo) # We don't really know how long servo needs to load a webpage, so we just wait 10s. sleep 10 # We dump the trace in ftrace format to disk hdc shell hitrace -b "${TRACE_BUFFER_SZ_KB}" --trace_finish -o /data/local/tmp/ohtrace.txt hdc shell snapshot_display -f /data/local/tmp/servo.jpeg hdc file recv /data/local/tmp/servo.jpeg test_output/servo_hos_screenshot.jpeg hdc file recv /data/local/tmp/ohtrace.txt test_output/servo.ftrace # To limit the logsize we only save logs from servo. hdc shell hilog --exit -D 0xE0C3 > test_output/servo.log # todo: Also benchmark some other websites.... - name: Upload artifacts uses: actions/upload-artifact@v4 with: path: test_output name: hos-${{ inputs.profile }}-test-output - name: Check success run: | # would be empty if servo crashed. servo_pid=$(hdc shell pidof org.servo.servo) [[ $servo_pid =~ ^[0-9]+$ ]] || { echo "It looks like servo crashed!" ; exit 1; } # If the grep fails, then the trace output for the "page loaded" prompt is missing grep 'org\.servo\.servo-.* tracing_mark_write.*PageLoadEndedPrompt' test_output/servo.ftrace bench-harmonyos-aarch64: name: Benching HarmonyOS aarch64 continue-on-error: true runs-on: hos-runner needs: test-harmonyos-aarch64 if: github.repository == 'servo/servo' steps: - uses: actions/download-artifact@v4 with: # Name of the artifact to download. # If unspecified, all artifacts for the run are downloaded. name: servoshell-hos-${{ inputs.profile }}.hap - name: Test hdc device # First we ensure a device is actually connected and working. run: hdc list targets && hdc shell echo hello world - name: Sign the hap run: | ls -la /usr/bin/sign-hos.sh servoshell-default-unsigned.hap servoshell-hos-signed.hap - name: Install run: | # Uninstall first. hdc is not very reliable in terms of exiting with an error, so we uninstall first # to make sure we don't use a previous version if installation failed for some reason. hdc uninstall org.servo.servo hdc install -r servoshell-hos-signed.hap - uses: actions/checkout@v4 if: github.event_name != 'pull_request_target' with: fetch-depth: 0 # This is necessary to checkout the pull request if this run was triggered via a # `pull_request_target` event. - uses: actions/checkout@v4 if: github.event_name == 'pull_request_target' with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 - name: Setup Python uses: ./.github/actions/setup-python - name: Getting hitrace-bench version run: echo "INSTALLED_HITRACE_BENCH_VERSION=$(hitrace-bench --version | awk '{print $2}')" >> $GITHUB_ENV - name: Install hitrace-bench run: cargo install --locked hitrace-bench --version $HITRACE_BENCH_VERSION if: ${{ env.INSTALLED_HITRACE_BENCH_VERSION != env.HITRACE_BENCH_VERSION }} - name: "Run benchmark" run: hitrace-bench -r support/hitrace-bencher/runs.json --bencher -p ${{ inputs.profile }} continue-on-error: true - name: Run speedometer id: BencherRun run: ./mach test-speedometer-ohos --bmf-output speedometer.json --profile ${{ inputs.profile }} continue-on-error: true - name: Create empty speedometer.json if failed run: touch speedometer.json if: ${{ steps.BencherRun.outcome == 'failure' }} - name: Getting model name # awk is used to remove trailing spaces run: | echo "MODEL_NAME=$(hdc shell param get const.product.name | awk '{$1=$1;print}' )" >> $GITHUB_ENV - name: Combining bencher files run: jq --compact-output --slurp add speedometer.json bench.json > combined-bencher.json - uses: bencherdev/bencher@main # set options - name: Set bencher opts for PRs (label try run) if: github.event_name == 'pull_request_target' run: | echo "RUN_BENCHER_OPTIONS=--branch ${{ github.event.number }}/PR \ --start-point ${{ github.base_ref }} \ --start-point-hash ${{ github.event.pull_request.base.sha }} \ --start-point-reset \ --start-point-clone-thresholds" >> "$GITHUB_ENV" - name: Set bencher opts for main if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} run: | echo "RUN_BENCHER_OPTIONS=--branch main" >> "$GITHUB_ENV" - name: Set bencher opts for try branch if: ${{ github.event_name == 'push' && github.ref_name == 'try' }} run: | git remote add upstream https://github.com/servo/servo git fetch upstream main echo "RUN_BENCHER_OPTIONS=--branch try \ --hash $(git rev-parse HEAD~1) \ --start-point main \ --start-point-hash $(git merge-base upstream/main HEAD) \ --start-point-clone-thresholds \ --start-point-reset" >> "$GITHUB_ENV" - name: Uploading to bencher.dev # Note: That e.g. `--start-point` is ignored if it is an empty string, # which should be the case on e.g. normal push workflows on main. run: | bencher run --adapter json \ --file combined-bencher.json \ --project '${{ env.BENCHER_PROJECT }}' \ --token '${{ secrets.BENCHER_API_TOKEN }}' \ --github-actions '${{ secrets.GITHUB_TOKEN }}' \ --testbed="$MODEL_NAME" \ $RUN_BENCHER_OPTIONS - name: Success if: ${{ !contains(steps.*.outcome, 'failure') && !contains(steps.*.outcome, 'cancelled') }} run: exit 0 - name: Failure if: contains(steps.*.outcome, 'failure') || contains(steps.*.outcome, 'cancelled') run: exit 1