Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/trusty/trusty/kernel/lib/metrics/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 13 kB image not shown  

Quelle  metrics.c

  Sprache: C
 

/*
 * Copyright (c) 2021, Google Inc. All rights reserved
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */


#include <assert.h>
#include <err.h>
#include <interface/metrics/consumer.h>
#include <kernel/mutex.h>
#include <lib/dpc.h>
#include <lib/trusty/handle.h>
#include <lib/trusty/ipc.h>
#include <lib/trusty/ipc_msg.h>
#include <lib/trusty/trusty_app.h>
#include <lk/init.h>
#include <lk/trace.h>
#include <string.h>
#include <trusty/uuid.h>

#define LOCAL_TRACE (0)

/*
 * Format of the payload is "<UUID>:<app name>", with neither UUID nor app name
 * being null-terminated. However, unlike APP_NAME_MAX_SIZE, UUID_STR_SIZE
 * counts the null character. Hence, the maximum size of an app name is
 * METRICS_MAX_APP_ID_LEN - UUID_STR_SIZE.
 */

static_assert(UUID_STR_SIZE <= METRICS_MAX_APP_ID_LEN);
#define APP_NAME_MAX_SIZE (METRICS_MAX_APP_ID_LEN - UUID_STR_SIZE)

/**
 * enum chan_state - states of the metrics consumer channel event handler
 * CHAN_STATE_WAITING_CHAN_READY:
 *      Inital state of the channel handler. At this point we are waiting for an
 *      IPC_HANDLE_POLL_READY channel event that signifies that metrics consumer
 *      connection is ready for use. After consuming this event, we transition
 *      to %CHAN_STATE_IDLE state.
 * CHAN_STATE_IDLE:
 *      While in this state we (2) can not consume any events from the channel
 *      (1) can only send one message over the channel. Once a message is sent,
 *      we transition to either %CHAN_STATE_WAITING_CRASH_RESP or
 *      %CHAN_STATE_WAITING_EXIT_RESP or %CHAN_STATE_WAITING_EVENT_DROP_RESP
 *      depending on what message was sent.
 * CHAN_STATE_WAITING_CRASH_RESP:
 *      In this state we are waiting for a response to a message about an app
 *      crash.  After receiving the response message, we transition to
 *      %CHAN_STATE_IDLE state.
 * CHAN_STATE_WAITING_EXIT_RESP:
 *      In this state we are waiting for a response to a message about an app
 *      crash.  After receiving the response message, we transition to
 *      %CHAN_STATE_IDLE state.
 * CHAN_STATE_WAITING_EVENT_DROP_RESP:
 *      In this state we are waiting for a response to a message about an event
 *      drop. After receiving the response message, we transition to
 *      %CHAN_STATE_IDLE state.
 */

enum chan_state {
    CHAN_STATE_WAITING_CHAN_READY = 0,
    CHAN_STATE_IDLE = 1,
    CHAN_STATE_WAITING_CRASH_RESP = 2,
    CHAN_STATE_WAITING_EXIT_RESP = 3,
    CHAN_STATE_WAITING_EVENT_DROP_RESP = 4,
};

struct metrics_ctx {
    struct handle* chan;
    enum chan_state chan_state;
    bool event_dropped;
};

static struct metrics_ctx ctx;
static mutex_t ctx_lock = MUTEX_INITIAL_VALUE(ctx_lock);

static int recv_resp(struct handle* chan, uint32_t cmd) {
    int rc;
    struct ipc_msg_info msg_info;
    struct metrics_resp resp;

    rc = ipc_get_msg(chan, &msg_info);
    if (rc != NO_ERROR) {
        TRACEF("failed (%d) to get message\n", rc);
        return rc;
    }

    struct iovec_kern iov = {
            .iov_base = &resp,
            .iov_len = sizeof(resp),
    };
    struct ipc_msg_kern ipc_msg = {
            .num_iov = 1,
            .iov = &iov,
            .num_handles = 0,
            .handles = NULL,
    };
    rc = ipc_read_msg(chan, msg_info.id, 0, &ipc_msg);
    ipc_put_msg(chan, msg_info.id);

    if (rc < 0) {
        TRACEF("failed (%d) ipc_read_msg().\n", rc);
        return rc;
    }

    if (rc != sizeof(resp)) {
        TRACEF("unexpected number of bytes received: %d.\n", rc);
        return ERR_BAD_LEN;
    }

    if (resp.cmd != (cmd | METRICS_CMD_RESP_BIT)) {
        TRACEF("unknown command received: %u %u.\n", resp.cmd, cmd);
        return ERR_CMD_UNKNOWN;
    }

    if (resp.status != METRICS_NO_ERROR) {
        TRACEF("event report failure: %d.\n", resp.status);
        /* This error is not severe enough to close the connection. */
    }

    return NO_ERROR;
}

static int send_req(struct handle* chan,
                    struct ipc_msg_kern* ipc_msg,
                    size_t total_len) {
    int rc = ipc_send_msg(chan, ipc_msg);
    if (rc < 0) {
        TRACEF("failed (%d) to send message\n", rc);
        return rc;
    }

    if (rc != (int)total_len) {
        TRACEF("unexpected number of bytes sent: %d\n", rc);
        return ERR_BAD_LEN;
    }

    return NO_ERROR;
}

static int report_crash(struct handle* chan,
                        struct trusty_app* app,
                        const struct trusty_error_args* error_args) {
    int rc;
    struct metrics_req req = {};
    struct metrics_report_crash_req args = {};
    size_t total_len;

    DEBUG_ASSERT(is_mutex_held(&ctx_lock));

    uuid_to_str(&app->props.uuid, args.app_id);

    req.cmd = METRICS_CMD_REPORT_CRASH;
    args.crash_reason = error_args->reason;
    args.far = error_args->far;
    memcpy(args.far_hash, error_args->far_hash, sizeof(args.far_hash));
    args.elr = error_args->elr;
    memcpy(args.elr_hash, error_args->elr_hash, sizeof(args.elr_hash));
    args.is_hash = error_args->is_hash;

    struct iovec_kern iovs[] = {
            {
                    .iov_base = &req,
                    .iov_len = sizeof(req),
            },
            {
                    .iov_base = &args,
                    .iov_len = sizeof(args),
            },
    };
    struct ipc_msg_kern ipc_msg = {
            .num_iov = countof(iovs),
            .iov = iovs,
    };

    total_len = sizeof(req) + sizeof(args);
    rc = send_req(chan, &ipc_msg, total_len);
    if (rc != NO_ERROR) {
        TRACEF("failed (%d) report app crash\n", rc);
        return rc;
    }

    return NO_ERROR;
}

static int report_exit(struct handle* chan,
                        struct trusty_app* app,
                        const struct trusty_error_args* error_args) {
    int rc;
    struct metrics_req req = {};
    struct metrics_report_exit_req args = {};
    size_t total_len;

    DEBUG_ASSERT(is_mutex_held(&ctx_lock));

    uuid_to_str(&app->props.uuid, args.app_id);

    req.cmd = METRICS_CMD_REPORT_EXIT;
    args.exit_code = error_args->reason;

    struct iovec_kern iovs[] = {
            {
                    .iov_base = &req,
                    .iov_len = sizeof(req),
            },
            {
                    .iov_base = &args,
                    .iov_len = sizeof(args),
            },
    };
    struct ipc_msg_kern ipc_msg = {
            .num_iov = countof(iovs),
            .iov = iovs,
    };

    total_len = sizeof(req) + sizeof(args);
    rc = send_req(chan, &ipc_msg, total_len);
    if (rc != NO_ERROR) {
        TRACEF("failed (%d) report app exit\n", rc);
        return rc;
    }

    return NO_ERROR;
}

static int report_event_drop(struct handle* chan) {
    int rc;
    struct metrics_req req;

    DEBUG_ASSERT(is_mutex_held(&ctx_lock));

    req.cmd = METRICS_CMD_REPORT_EVENT_DROP;
    req.reserved = 0;

    struct iovec_kern iov = {
            .iov_base = &req,
            .iov_len = sizeof(req),
    };
    struct ipc_msg_kern ipc_msg = {
            .num_iov = 1,
            .iov = &iov,
    };

    rc = send_req(chan, &ipc_msg, sizeof(req));
    if (rc != NO_ERROR) {
        TRACEF("failed (%d) report event drop\n", rc);
        return rc;
    }

    return NO_ERROR;
}

static int on_ta_crash(struct trusty_app* app, const struct trusty_error_args* error_args) {
    int rc;

    mutex_acquire(&ctx_lock);

    if (ctx.chan_state != CHAN_STATE_IDLE) {
        TRACEF("there is a metrics event still in progress or metrics TA "
               "is unavailable\n");
        ctx.event_dropped = true;
        goto out;
    }

    if (!ctx.chan) {
        TRACEF("failed get metrics consumer channel\n");
        goto out;
    }

    if(error_args->is_crash) {
        rc = report_crash(ctx.chan, app, error_args);
        ctx.chan_state = CHAN_STATE_WAITING_CRASH_RESP;
    }
    else {
        rc = report_exit(ctx.chan, app, error_args);
        ctx.chan_state = CHAN_STATE_WAITING_EXIT_RESP;
    }
    if (rc != NO_ERROR) {
        TRACEF("failed (%d) report app crash\n", rc);
        goto err;
    }

    goto out;

err:
    handle_close(ctx.chan);
    ctx.chan = NULL;
out:
    mutex_release(&ctx_lock);
    /*
     * Returning an error here will bring down the kernel. Metrics reporting
     * isn't critical. So, we always return NO_ERROR. If something goes wrong,
     * printing an error should suffice.
     */

    return NO_ERROR;
}

static struct trusty_app_notifier notifier = {
        .crash = on_ta_crash,
};

static void handle_chan(struct dpc* work) {
    int rc;
    uint32_t event;

    mutex_acquire(&ctx_lock);

    event = ctx.chan->ops->poll(ctx.chan, ~0U, true);
    if (event & IPC_HANDLE_POLL_HUP) {
        TRACEF("received IPC_HANDLE_POLL_HUP, closing channel\n");
        goto err;
    }

    switch (ctx.chan_state) {
    case CHAN_STATE_WAITING_CHAN_READY:
        if (!(event & IPC_HANDLE_POLL_READY)) {
            TRACEF("unexpected channel event: 0x%x\n", event);
            goto err;
        }

        ctx.chan_state = CHAN_STATE_IDLE;
        goto out;

    case CHAN_STATE_IDLE:
        TRACEF("unexpected channel event: 0x%x\n", event);
        goto err;

    case CHAN_STATE_WAITING_CRASH_RESP:
        if (!(event & IPC_HANDLE_POLL_MSG)) {
            TRACEF("unexpected channel event: 0x%x\n", event);
            goto err;
        }

        rc = recv_resp(ctx.chan, METRICS_CMD_REPORT_CRASH);
        if (rc != NO_ERROR) {
            TRACEF("failed (%d) receive response\n", rc);
            goto err;
        }

        ctx.chan_state = CHAN_STATE_IDLE;

        if (ctx.event_dropped) {
            rc = report_event_drop(ctx.chan);
            if (rc != NO_ERROR) {
                TRACEF("failed (%d) report event drop\n", rc);
                goto err;
            }
            ctx.chan_state = CHAN_STATE_WAITING_EVENT_DROP_RESP;
            goto out;
        }

        goto out;

    case CHAN_STATE_WAITING_EXIT_RESP:
        if (!(event & IPC_HANDLE_POLL_MSG)) {
            TRACEF("unexpected channel event: 0x%x\n", event);
            goto err;
        }

        rc = recv_resp(ctx.chan, METRICS_CMD_REPORT_EXIT);
        if (rc != NO_ERROR) {
            TRACEF("failed (%d) receive response\n", rc);
            goto err;
        }

        ctx.chan_state = CHAN_STATE_IDLE;

        if (ctx.event_dropped) {
            rc = report_event_drop(ctx.chan);
            if (rc != NO_ERROR) {
                TRACEF("failed (%d) report event drop\n", rc);
                goto err;
            }
            ctx.chan_state = CHAN_STATE_WAITING_EVENT_DROP_RESP;
            goto out;
        }

        goto out;

    case CHAN_STATE_WAITING_EVENT_DROP_RESP:
        if (!(event & IPC_HANDLE_POLL_MSG)) {
            TRACEF("unexpected channel event: 0x%x\n", event);
            goto err;
        }

        rc = recv_resp(ctx.chan, METRICS_CMD_REPORT_EVENT_DROP);
        if (rc != NO_ERROR) {
            TRACEF("failed (%d) receive response\n", rc);
            goto err;
        }

        ctx.chan_state = CHAN_STATE_IDLE;
        ctx.event_dropped = false;
        goto out;
    }

err:
    handle_close(ctx.chan);
    ctx.chan = NULL;
out:
    mutex_release(&ctx_lock);
}

static struct dpc chan_event_work = {
        .node = LIST_INITIAL_CLEARED_VALUE,
        .cb = handle_chan,
};

static void on_handle_event(struct handle_waiter* waiter) {
    int rc = dpc_enqueue_work(NULL, &chan_event_work, false);
    if (rc != NO_ERROR) {
        TRACEF("failed (%d) to enqueue dpc work\n", rc);
    }
}

static struct handle_waiter waiter = {
        .node = LIST_INITIAL_CLEARED_VALUE,
        .notify_proc = on_handle_event,
};

static void metrics_init(uint level) {
    int rc = ipc_port_connect_async(&kernel_uuid, METRICS_CONSUMER_PORT,
                                    IPC_PORT_PATH_MAX,
                                    IPC_CONNECT_WAIT_FOR_PORT, &ctx.chan);
    if (rc) {
        TRACEF("failed (%d) to connect to port\n", rc);
        goto err_port_connect;
    }

    rc = trusty_register_app_notifier(¬ifier);
    if (rc) {
        TRACEF("failed (%d) to register app notifier\n", rc);
        goto err_app_notifier;
    }

    ctx.chan_state = CHAN_STATE_WAITING_CHAN_READY;
    handle_add_waiter(ctx.chan, &waiter);

    return;

err_app_notifier:
    handle_close(ctx.chan);
    ctx.chan = NULL;
err_port_connect:
    return;
}

/* Need to init before (LK_INIT_LEVEL_APPS - 1) to register an app notifier. */
LK_INIT_HOOK(metrics, metrics_init, LK_INIT_LEVEL_APPS - 2);

Messung V0.5 in Prozent
C=93 H=85 G=88

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet am  2026-06-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.