Bash程序  |  309行  |  9.35 KB

#!/bin/bash
#
# Copyright (c) 2011-2014, Intel Corporation
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

set -ueo pipefail

# In order to dispatch log properly 4 output streams are available:
# - 1 info
# - 2 error
# - 3 (reserved)
# - 4 standard
# - 5 warning

# Leave standard output unmodified
exec 4>&1
# If the nonverbose long option is provided, do not output info log lines prefixed on stderr.
if test "$1" == --nonverbose
then
    shift
    exec 1>/dev/null
else
    exec 1> >(sed "s/^/($$) Info: /" >&2)
fi
# Prefix all warning and error log lines and redirect them to stderr
exec 5> >(sed "s/^/($$) Warning: /" >&2)
exec 2> >(sed "s/^/($$) Error: /" >&2)

# Get script arguments
validationEnabled="false"
if [ "$1" = "--validate" ]; then
    validationEnabled="true"
    shift
fi
PFWconfigurationFilePath="$1"; shift
CriterionFilePath="$1"; shift
xmlDomainFilePath="$1"; shift

# Set constant variables
testPlatform="test-platform_host"
remoteProcess="remote-process_host"

hostConfig="hostConfig.py"
PFWScriptGenerator="PFWScriptGenerator.py"
portAllocator="portAllocator.py"

TPHost=127.0.0.1
PFWHost=127.0.0.1
TPCreated=false

HostRoot="$ANDROID_HOST_OUT"
TargetRoot="$ANDROID_PRODUCT_OUT/system"

# Global variables
TPSocket=5003
PFWSocket=5000
PFWStartTimeout=60

tmpDir=$(mktemp -d)
tmpFile=$(mktemp --tmpdir="$tmpDir")

# [Workaround]
# The build system does not preserve execution right in external prebuild
for file in "$testPlatform" "$remoteProcess" "$hostConfig" "$PFWScriptGenerator" "$portAllocator"
do
    chmod +x "${HostRoot}/bin/${file}"
done

# Set environment paths
export LD_LIBRARY_PATH="$HostRoot/lib:${LD_LIBRARY_PATH:-}"

# Setup clean trap, it will be called automatically on exit
clean_up () {
    status=$?
    set +e # An error should not abort clean up

    # Exit the test-platform only if it was created by this process
    if $TPCreated
    then
        echo "Exiting test-platform listening on port $TPSocket"
        $remoteProcess $TPHost $TPSocket exit
    fi

    echo "Cleaning $tmpFile ..."
    rm "$tmpFile" || true

    if [ "$validationEnabled" = "true" ]; then
        echo "Cleaning $tmpDir/Schemas ..."
        rm -r "$tmpDir/Schemas" || true
        rmdir "$tmpDir" || true
    fi

    echo "Cleaning status: $status ..."
    return $status
}

trap clean_up SIGHUP SIGINT SIGTERM EXIT

# Create a symlink link to rename a library.
# Eg: /lib/ contains the lib mylib_host.so but it must be found under the name
# mylib.so. linkLibrary mylib_host.so mylib.so will create a symlink in mylib_host.so's folder
# called mylib.so, pointing to mylib_host.so
linkLibrary () {
    local src="$1"
    local dest="$2"
    local path=$(find $HostRoot/lib -name "$src")

    # Check that both names are different, otherwise there is an error
    if ! test "$(basename "$path")" != "$dest"
    then
        echo "Cannot link $dest to $src !"
        return 1
    fi

    # Check that destination file does not already exist
    if ! test -f "$(dirname "$path")/$dest"
    then
        # Create the symlink. Do not force if it has been created after the previous
        # test, in this case simply ignore the error
        ln -s "$src" "$(dirname "$path")/$dest" || true
    fi
    return 0
}

# The retry function will execute the provided command nbRety times util success.
# It also sleep sleepTime second between each retry.
retry() {
    local command=$1
    local nbRetry=$2
    local sleepTime=$3
    local retry=0
    while ! $command 2>/dev/null >&2
    do
        (($retry < $nbRetry)) || return 1
        retry=$(($retry + 1))
        sleep $sleepTime
    done
    return 0;
}

# Configure the PFW main config file for simulation
formatConfigFile () {
    "$hostConfig" $PFWSocket "$(readlink -f "$(dirname "$1")")" <"$1"
}

# The initTestPlatform starts a testPlatform instance with the config file given in argument.
# It will also set the PFWSocket global variable to the PFW remote processor listening socket.
initTestPlatform () {
    # Format the PFW config file
    formatConfigFile "$1" >"$tmpFile"

    # Start test platform
    echo "Starting test-platform on port $TPSocket ..."
    $testPlatform -d "$tmpFile" $TPSocket 2>&5

    res=$?
    if test $res -ne 0
    then
        echo "Unable to launch the simulation platform (using socket $TPSocket)" >&5
        return 4
    fi

    echo "Test platform successfuly loaded!"
    return 0
}

# Execute a command for each input line, stopping in case of error
forEachLine () {
    xargs -I@ sh -c "echo \> $1;$1 || exit 255"
}

# Configure test platform (mainly criterion) and start the PFW
launchTestPlatform () {
    local TPSendCommand="$remoteProcess $TPHost $TPSocket"
    sed -e 's/InclusiveCriterion/createInclusiveSelectionCriterionFromStateList/' \
        -e 's/ExclusiveCriterion/createExclusiveSelectionCriterionFromStateList/' \
        -e 's/[[:space:]]:[[:space:]]/ /g' "$CriterionFilePath" |
        forEachLine "$TPSendCommand @"

    $TPSendCommand setFailureOnMissingSubsystem false
    $TPSendCommand setFailureOnFailedSettingsLoad false
    $TPSendCommand setValidateSchemasOnStart $validationEnabled

    echo "Asking test-platform (port $TPSocket) to start a new PFW instance (listening on port $PFWSocket) ..."
    $TPSendCommand start
    res=$?
    if test $res -ne 0
    then
        echo "Unable to launch the parameter framework (using port $PFWSocket)" >&5
        return 5
    fi

    echo "Parameter framework successfully started!"
    return 0
}

startPFW () {
    # Init the test-platform
    initTestPlatform "$PFWconfigurationFilePath" || return 1
    TPCreated=true

    # Ask the test-platform to start the PFW
    if ! launchTestPlatform "$CriterionFilePath"
    then
        # If PFW didn't start, exit the current test-platform, and return failure in
        # order to choose new socket ports
        echo "Exiting test-platform listening on port $TPSocket"
        $remoteProcess $TPHost $TPSocket exit
        TPCreated=false
        return 1
    fi
}

# Get a new pair of available ports for TP and PFW sockets
changeSocketsPorts() {
    TPSocket=$($portAllocator) || return 1
    PFWSocket=$($portAllocator) || return 1
}

# Start the pfw using different socket if it fails
safeStartPFW () {
    local retry=0
    local nbRetry=1000 # Workaround to avoid build failure, it very very rarely fail this many time

    # Choose a new pair of socket ports
    changeSocketsPorts
    echo "Trying to start test-platform and PFW, with socket $TPSocket and $PFWSocket"

    while ! startPFW
    do
        (($retry < $nbRetry)) || return 1
        retry=$(($retry + 1))

        # Choose a new pair of socket ports
        changeSocketsPorts || continue

        echo "Unable to start PFW, try again with socket $TPSocket and $PFWSocket"
    done
}

deleteEscapedNewLines () {
    sed -r ':a;/\\$/{N;s/\\\n//;ba}'
}

copySchemaFiles() {
    cp -r "$HostRoot"/etc/parameter-framework/Schemas "$tmpDir/Schemas"
}

# Copy the schema files needed for validation
if [ "$validationEnabled" = "true" ]; then
    copySchemaFiles
fi

# The PFW looks for a libremote-processor.so library, not a libremote-processor_host.so
linkLibrary libremote-processor_host.so libremote-processor.so

# Start test platform and the PFW
# Start the pfw using different socket if it fails
safeStartPFW

PFWSendCommand="$remoteProcess $PFWHost $PFWSocket"

$PFWSendCommand setTuningMode on

# Send the xml domain tunning file
if test -s "$xmlDomainFilePath"
then
    echo "Import the xml domain tunning file: $(readlink -e $xmlDomainFilePath)"
    $PFWSendCommand importDomainsWithSettingsXML "$(readlink -e $xmlDomainFilePath)"
fi

# Send the extended domain description routing files converted to pfw commands
m4 "$@" |
    "$PFWScriptGenerator" --output-kind pfw |
    deleteEscapedNewLines |
    forEachLine "$PFWSendCommand @" | sed '/^Done$/d'

# Export the global xml domains description
$PFWSendCommand getDomainsWithSettingsXML |
    # Delete trailing carriage return and format absolute paths
    sed -r -e 's/\r$//' \
           -e 's@(xsi:noNamespaceSchemaLocation=")'"$tmpDir"'/?@\1@' >&4