/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #define TLOG_TAG "lib_system_state" /** * long system_state_send_req() - sends request to system_state server * @req: the request header to send to the system_state server * @req_buf: the request payload to send to the system_state server * @req_buf_len: the length of the request payload @req_buf * @resp: buffer in which to store the response header * @resp_buf: buffer in which to store the response payload * @resp_buf_len: the size of the response buffer. Inout param, set * to the actual response payload length. * * Returns: NO_ERROR on success, negative error code on failure */ static long system_state_send_req(struct system_state_req* req, void* req_buf, size_t req_buf_len, struct system_state_resp* resp, void* resp_buf, size_t* resp_buf_len) { int ret; handle_t session = connect(SYSTEM_STATE_PORT, IPC_CONNECT_WAIT_FOR_PORT); if (session == INVALID_IPC_HANDLE) { TLOGE("%s: failed to connect\n", __func__); return ERR_IO; } ret = tipc_send2(session, req, sizeof(*req), req_buf, req_buf_len); if (ret < 0) { goto err_io; } if (((size_t)ret) != sizeof(*req) + req_buf_len) { ret = ERR_IO; goto err_io; } uevent_t uevt; ret = wait(session, &uevt, INFINITE_TIME); if (ret != NO_ERROR) { goto err_io; } ret = tipc_recv2(session, sizeof(*resp), resp, sizeof(*resp), resp_buf, *resp_buf_len); if (ret < 0) { goto err_io; } size_t read_len = (size_t)ret; if (read_len < sizeof(*resp)) { TLOGE("%s: short read (%zu)\n", __func__, read_len); ret = ERR_IO; goto err_io; } if (resp->cmd != (req->cmd | SYSTEM_STATE_CMD_RESP_BIT)) { TLOGE("%s: invalid response id (0x%x) for cmd (0x%x)\n", __func__, resp->cmd, req->cmd); ret = ERR_NOT_VALID; goto err_io; } close(session); *resp_buf_len = read_len - sizeof(*resp); return resp->result; err_io: close(session); TLOGE("%s: failed read_msg (%d)\n", __func__, ret); return ret; } int system_state_get_flag(enum system_state_flag flag, uint64_t* valuep) { int ret; struct system_state_req req = { .cmd = SYSTEM_STATE_CMD_GET_FLAG, }; struct system_state_get_flag_req get_flag_req = { .flag = flag, }; struct system_state_resp resp; struct system_state_get_flag_resp get_flag_resp; size_t get_flag_resp_size = sizeof(get_flag_resp); ret = system_state_send_req(&req, &get_flag_req, sizeof(get_flag_req), &resp, &get_flag_resp, &get_flag_resp_size); if (ret) { TLOGE("%s: request failed (%d)\n", __func__, ret); return ret; } if (get_flag_resp_size != sizeof(get_flag_resp)) { TLOGE("%s: bad response size (%zd)\n", __func__, get_flag_resp_size); return ERR_IO; } if (get_flag_resp.flag != flag) { TLOGE("%s: bad response flag (%d)\n", __func__, get_flag_resp.flag); return ERR_IO; } *valuep = get_flag_resp.value; return 0; }