【小语法重点】result?.data?. errno === 0 前端语法“?“的含义

本文解析了JavaScript中?.?运算符在访问嵌套属性时的智能容错特性,展示了result?.data?.errno如何避免因对象不存在导致的错误,并通过实例说明其实用价值。

前端语法"?"的含义

result?.data?. errno === 0 如何理解呢?
这是js中的一种新语法。result?.data?.errno的意思是尝试获取result中的data中的error属性,它和result.data.errno的意思是一样的,但是比result.data.errno的容错性更高。

如果result对象中没有data属性,那么再获取errno时,代码容易报错,如下:

http://img.mukewang.com/climg/6036ff6b095f5a1303770112.jpg

http://img.mukewang.com/climg/6036ff7a09c7826406890115.jpg

而result?.data?.errno这种写法,代码会尝试查找errno,如果查找不到,会返回undefined,而不会报错:

http://img.mukewang.com/climg/6036ff9009146e5304290123.jpg

http://img.mukewang.com/climg/6036ff99099fb68903970096.jpg​

我进行了整合,你看对不对,并且深刻记忆这份代码 /****************************************************************************** * * Copyright (c) 2025 TP-LINK Technologies CO.,LTD. * All rights reserved. * * FILE NAME : nasw.c * VERSION : 1.0 * DESCRIPTION : 提供网络自动切换功能 * * AUTHOR : Sun Haoming (sunhaoming@tp-link.com.hk) * CREATE DATE : 10/09/2025 * * HISTORY : * 01 10/09/2025 Sun Haoming Create. * ******************************************************************************/ #include <stdio.h> #include <unistd.h> /* for chdir() */ #include <string.h> /* for strcmp() */ #include <errno.h> /* for errno */ #include <string.h> #include <linux/ethtool.h> #include <arpa/inet.h> #include <stdlib.h> #include "nasw.h" #include "dms_tool.h" #include "libdms.h" #include "libds.h" #include "packet.h" #include "nifc.h" /* 新增状态定义 */ #define PING_STATUS_UNKNOWN -1 #define PING_STATUS_FAILED 0 #define PING_STATUS_SUCCESS 1 /* 网络状态超时定义 */ #define NASW_NETWORK_CHECK_INTERVAL 10 // 网络检测间隔 #define NASW_SWITCH_DELAY 3 // 切换延迟时间 #define NASW_PHYSICAL_DEBOUNCE_DELAY 2 // 物理状态防抖延迟 #define NASW_LINK_CHANGE_DEBOUNCE 20 // 网络状态变化防抖时间(秒) /* 状态缓存结构 */ typedef struct { U8 last_phy_status; U8 last_internet_status; U8 last_auto_switch_wired; U8 last_internet_wired_enable; time_t last_change_time; S8 nasw_wired_diag; // 内部诊断结果(-1:未知 0:失败 1:成功) U8 ping_count; // 连续检测计数 int physical_debounce_timer; // 物理状态防抖定时器 time_t last_link_change; // 最后网络状态变化时间(防抖用) U8 phy_debounce_ready = 1; } NASW_STATE_CACHE; /* 全局变量 */ static NASW_STATE_CACHE g_state_cache = {0}; static int nasw_network_timer = -1; static int g_switch_delay_timer = -1; LOCAL void nasw_network_diagnose(void); LOCAL void nasw_switch_action(U8 target_mode); LOCAL void nasw_update_auto_switch(U8 phy_status, S8 wired_diag); LOCAL S8 nasw_do_ping_check(void); LOCAL void nasw_physical_debounce_handler(U32 phy_status); LOCAL void nasw_handle_physical_change(U8 new_status); /****************************************************************************** * Ping检测函数(需后续实现) ******************************************************************************/ LOCAL S8 nasw_do_ping_check(void) { // 实际实现需替换以下伪代码 /* if (ping_target("8.8.8.8") == SUCCESS) { return PING_STATUS_SUCCESS; } else { return PING_STATUS_FAILED; } */ return PING_STATUS_UNKNOWN; // 暂返回未知状态 } /****************************************************************************** * 网络诊断核心逻辑(修改版) ******************************************************************************/ LOCAL void nasw_network_diagnose(void) { LTE_CONFIG_INFO_DATA lte_config; if (0 != ds_read(LTE_INFO_DATA_PATH, &lte_config, sizeof(LTE_CONFIG_INFO_DATA))) { NASW_ERROR("读取LTE配置失败"); return; } // 仅在有卡有线模式下执行诊断(这里怎么确定有卡? ) if (lte_config.internet_wired_enable == 2 // auto模式 && g_state_cache.last_phy_status == 1) { // 物理连接存在 // 执行ping检测 S8 current_result = nasw_do_ping_check(); S8 last_result=1; // 更新连续检测状态 if (last_result == current_result) { g_state_cache.ping_count++; } else { g_state_cache.ping_count = 1; last_result = current_result; } // 连续两次检测判断(关键修改点) if (g_state_cache.ping_count >= 2) { // 更新内部诊断状态 g_state_cache.nasw_wired_diag = current_result; // B→C模式转换处理(无线有卡→插线→有线有卡) if (lte_config.auto_switch_wired == 0) { lte_config.auto_wired_internet_status = (current_result == PING_STATUS_SUCCESS) ? 1 : 0; NASW_INFO("B→C模式转换更新状态: %s", (current_result == PING_STATUS_SUCCESS) ? "通" : "断"); } NASW_INFO("有线诊断结果: %s", (current_result == PING_STATUS_SUCCESS) ? "通" : "断"); } } // 触发自动切换状态更新(使用内部诊断结果) nasw_update_auto_switch( g_state_cache.last_phy_status, g_state_cache.nasw_wired_diag ); // 保存配置状态 if (0 != ds_advanced_write(LTE_INFO_DATA_PATH, &lte_config, sizeof(lte_config), DS_FLAG_NOTIFY)) { NASW_ERROR("更新LTE配置失败"); } } LOCAL void nasw_update_auto_switch(U8 phy_status, S8 wired_diag) { LTE_CONFIG_INFO_DATA lte_config; if (0 != ds_read(LTE_INFO_DATA_PATH, &lte_config, sizeof(LTE_CONFIG_INFO_DATA))) { NASW_ERROR("读取LTE配置失败"); return; } U8 should_switch = 0; U8 new_switch_state = lte_config.auto_switch_wired; // 仅在有卡有线模式处理 if (lte_config.internet_wired_enable == 2) { /* 物理断开强制切4G */ if (phy_status == 0) { if (lte_config.auto_switch_wired != 0) { should_switch = 1; new_switch_state = 0; NASW_WARN("物理断开,强制切换到4G"); } } /* 物理连接时的诊断逻辑 */ else if (phy_status == 1) { // 场景1:当前4G模式且有线通畅 → 切有线 if (lte_config.auto_switch_wired == 0 && wired_diag == PING_STATUS_SUCCESS) { new_switch_state = 1; should_switch = 1; NASW_INFO("有线恢复,切换到有线"); } // 场景2:当前有线模式且诊断失败 → 切4G else if (lte_config.auto_switch_wired == 1 && wired_diag == PING_STATUS_FAILED) { new_switch_state = 0; should_switch = 1; NASW_ERROR("有线故障,切换到4G"); } } } // 立即执行切换(无延迟) if (should_switch) { nasw_switch_action(new_switch_state); } } /****************************************************************************** * 状态切换执行函数 ******************************************************************************/ LOCAL void nasw_switch_action(U8 target_mode) { LTE_CONFIG_INFO_DATA lte_config; if (0 != ds_read(LTE_INFO_DATA_PATH, &lte_config, sizeof(LTE_CONFIG_INFO_DATA))) { NASW_ERROR("读取LTE配置失败"); return; } NASW_INFO("执行即时切换: %s模式", target_mode ? "有线" : "4G"); /* 切换到有线模式 */ if (target_mode == 1) { nifc_enable_wired_network(); if (g_state_cache.nasw_wired_diag == PING_STATUS_SUCCESS) { lte_disable_4g_network(); } } /* 切换到4G模式 */ else { lte_enable_4g_network(); nifc_disable_wired_network_but_keep_connection(); } // 更新状态 lte_config.auto_switch_wired = target_mode; if (0 != ds_advanced_write(LTE_INFO_DATA_PATH, &lte_config, sizeof(lte_config), DS_FLAG_NOTIFY)) { NASW_ERROR("更新切换状态失败"); } NASW_INFO("已切换到: %s模式", target_mode ? "有线" : "4G"); } /****************************************************************************** 物理状态处理函数(完整防抖版) ******************************************************************************/ LOCAL void nasw_physical_debounce_handler(U32 phy_status) { // 统一处理拔插状态 NASW_INFO("物理状态确认: %s", (phy_status == 1) ? "已插入" : "已拔出"); // 更新物理状态缓存 g_state_cache.last_phy_status = (U8)phy_status; // 有线拔出时立即重置诊断状态 if (phy_status == 0) { NASW_INFO("有线拔出,重置诊断状态"); g_state_cache.nasw_wired_diag = PING_STATUS_UNKNOWN; g_state_cache.ping_count = 0; } // 触发网络诊断 nasw_network_diagnose(); // 重置定时器ID g_state_cache.physical_debounce_timer = -1; } LOCAL void nasw_handle_physical_change(U8 new_status) { // 清除现有防抖定时器 if (g_state_cache.physical_debounce_timer != -1) { inet_del_timer(g_state_cache.physical_debounce_timer); g_state_cache.physical_debounce_timer = -1; } // 创建新的防抖定时器(拔插均防抖) g_state_cache.physical_debounce_timer = inet_add_timer( (void (*)(U32))nasw_physical_debounce_handler, (U32)new_status, NASW_PHYSICAL_DEBOUNCE_DELAY, EXECUTE_SINGLE ); if (g_state_cache.physical_debounce_timer == -1) { NASW_ERROR("物理防抖定时器创建失败"); } else { NASW_INFO("物理状态变化防抖中: %s->%s (%d秒后确认)", g_state_cache.last_phy_status ? "插入" : "拔出", new_status ? "插入" : "拔出", NASW_PHYSICAL_DEBOUNCE_DELAY); } } /****************************************************************************** * 初始化与启动函数 ******************************************************************************/ LOCAL S32 nasw_init(void) { memset(&g_state_cache, 0, sizeof(NASW_STATE_CACHE)); g_state_cache.nasw_wired_diag = PING_STATUS_UNKNOWN; g_state_cache.physical_debounce_timer = -1; g_state_cache.last_link_change = time(NULL); return OK; } LOCAL S32 nasw_start(void) { PHY_STATUS phy_status; LINK_STATUS link_status; LTE_CONFIG_INFO_DATA lte_config; NASW_INFO("启动NASW模块..."); // 读取物理状态 if (0 == ds_read(PHY_STATUS_PATH, &phy_status, sizeof(PHY_STATUS))) { NASW_ERROR("读取PHY状态失败"); return ERROR; } // 读取网络状态 if (0 == ds_read(LINK_STATUS_PATH, &link_status, sizeof(LINK_STATUS))) { NASW_ERROR("读取LINK状态失败"); return ERROR; } // 初始化LTE配置 if (0 == ds_read(LTE_INFO_DATA_PATH, &lte_config, sizeof(LTE_CONFIG_INFO_DATA))) { NASW_ERROR("读取LTE配置失败,使用默认值"); memset(&lte_config, 0, sizeof(lte_config)); } // 设置初始状态缓存 g_state_cache.last_phy_status = phy_status.ether; g_state_cache.last_internet_status = link_status.internet_status; g_state_cache.last_auto_switch_wired = lte_config.auto_switch_wired; g_state_cache.last_internet_wired_enable = lte_config.internet_wired_enable g_state_cache.last_change_time = time(NULL); if (lte_config.internet_wired_enable != 2) { NASW_ERROR("non-auto mode, self-selected internet mode, WIRED=%d)", lte_config.internet_wired_enable); lte_config.auto_switch_wired = 2; ds_write(LTE_INFO_DATA_PATH, &lte_config, sizeof(lte_config)); } /* 仅当 internet_wired_enable == 2 时才处理 auto_switch_wired */ if (lte_config.internet_wired_enable == 2) { if (phy_status.ether == 1) { lte_config.auto_switch_wired = 1; } else { lte_config.auto_switch_wired = 0; } if (0 != ds_advanced_write(LTE_INFO_DATA_PATH, &lte_config, sizeof(lte_config), DS_FLAG_NOTIFY)) { NASW_ERROR("写入初始LTE配置失败"); } } NASW_INFO("执行首次网络诊断..."); nasw_network_diagnose(); // 同步执行 // 启动网络诊断定时器 nasw_network_timer = inet_add_timer( (void (*)(U32))nasw_network_diagnose, // 回调函数 0, // 参数 NASW_NETWORK_CHECK_INTERVAL, // 间隔时间 EXECUTE_FOREVER // 永久执行 ); if (nasw_network_timer == -1) { NASW_ERROR("创建网络诊断定时器失败"); } if (lte_config.internet_wired_enable == 1) { NASW_INFO("NASW未处于auto模式,初始模式: %s", lte_config.internet_wired_enable ? "有线" : "4G"); } else if (lte_config.internet_wired_enable == 2) { NASW_INFO("NASW启动完成,初始模式: %s", lte_config.auto_switch_wired ? "有线" : "4G"); } return OK; } /****************************************************************************** * reload函数(含防抖和B→C处理) ******************************************************************************/ LOCAL S32 nasw_reload(DS_MSG *msg) { if (!msg) return OK; PHY_STATUS phy_status = {0}; LINK_STATUS link_status = {0}; LTE_CONFIG_INFO_DATA lte_config = {0}; BOOL phy_changed = 0; BOOL link_changed = 0; BOOL lte_changed = 0; // 检查 PHY_STATUS_PATH 变化 if (ds_path_id_exist(msg->id, msg->num, PHY_STATUS_PATH)) { if (0 == ds_read(PHY_STATUS_PATH, &phy_status, sizeof(PHY_STATUS))) { NASW_ERROR("读取PHY状态失败"); return ERROR; } if (g_state_cache.last_phy_status != phy_status.ether) { phy_changed = 1; g_state_cache.last_phy_status = phy_status.ether; } } // 检查 LINK_STATUS_PATH 变化 if (ds_path_id_exist(msg->id, msg->num, LINK_STATUS_PATH)) { if (0 == ds_read(LINK_STATUS_PATH, &link_status, sizeof(LINK_STATUS))) { NASW_ERROR("读取LINK状态失败"); return ERROR; } if (g_state_cache.last_internet_status != link_status.internet_status) { link_changed = 1; g_state_cache.last_internet_status = link_status.internet_status; } } // 检查 LTE_INFO_DATA_PATH 变化 if (ds_path_id_exist(msg->id, msg->num, LTE_INFO_DATA_PATH)) { if (0 == ds_read(LTE_INFO_DATA_PATH, &lte_config, sizeof(LTE_CONFIG_INFO_DATA))) { NASW_ERROR("读取LTE配置失败"); return ERROR; } // 处理非自动模式 if (lte_config.internet_wired_enable != 2) { NASW_INFO("非自动模式(WIRED=%d)", lte_config.internet_wired_enable); lte_config.auto_switch_wired = 2; if (0 != ds_write(LTE_INFO_DATA_PATH, &lte_config, sizeof(lte_config))) { NASW_ERROR("web切换至非auto模式"); } } // 处理自动模式状态变化 if (lte_config.internet_wired_enable == 2) { if (g_state_cache.last_auto_switch_wired != lte_config.auto_switch_wired) { lte_changed = 1; g_state_cache.last_auto_switch_wired = lte_config.auto_switch_wired; } } } // B→C模式特殊处理(无线有卡→插线→有线有卡) if (phy_changed && phy_status.ether == 1 && lte_config.internet_wired_enable == 2 && lte_config.auto_switch_wired == 0) { NASW_INFO("B→C模式转换(插线),重置诊断状态"); g_state_cache.nasw_wired_diag = PING_STATUS_UNKNOWN; g_state_cache.ping_count = 0; nasw_network_diagnose(); // 立即触发 } // C状态处理:有线物理连接+Ping检测 if (lte_config.internet_wired_enable == 2 && phy_status.ether == 1 && lte_config.auto_switch_wired == 1) { nasw_network_diagnose(); // 持续监控 } // 网络状态变化处理(带防抖) if (link_changed) { time_t now = time(NULL); // 防抖处理:20秒内不重复触发 if (now - g_state_cache.last_link_change > NASW_LINK_CHANGE_DEBOUNCE) { NASW_INFO("检测到网络状态变化:%d -> %d(防抖通过)", g_state_cache.last_internet_status, link_status.internet_status); // 更新最后变化时间 g_state_cache.last_link_change = now; // 物理连接存在时触发诊断 if (g_state_cache.last_phy_status == 1) { nasw_network_diagnose(); } } else { NASW_ERROR("网络状态变化%ds内被过滤(防抖)", (int)(now - g_state_cache.last_link_change)); } } // 处理物理连接状态变化(有线插入/拔出) if (phy_changed) { NASW_INFO("物理连接状态变化:%d -> %d", g_state_cache.last_phy_status, phy_status.ether); // 触发物理状态变化处理(带防抖机制) nasw_handle_physical_change(phy_status.ether); // 有线拔出时立即重置诊断状态 if (phy_status.ether == 0) { NASW_INFO("检测到有线拔出,重置诊断状态"); g_state_cache.nasw_wired_diag = PING_STATUS_UNKNOWN; g_state_cache.ping_count = 0; } } // 处理切换模式变化 if (lte_changed) { NASW_INFO("切换模式变更:%d -> %d", g_state_cache.last_auto_switch_wired, lte_config.auto_switch_wired); // 立即触发诊断(确保状态同步) nasw_network_diagnose(); } return OK; } /****************************************************************************** * 停止函数(完整清理资源) ******************************************************************************/ LOCAL S32 nasw_stop(void) { NASW_INFO("正在停止NASW模块..."); // 1. 清理网络诊断定时器 if (nasw_network_timer != -1) { inet_del_timer(nasw_network_timer); nasw_network_timer = -1; NASW_INFO("网络诊断定时器已清理"); } // 2. 清理切换延迟定时器 if (g_switch_delay_timer != -1) { inet_del_timer(g_switch_delay_timer); g_switch_delay_timer = -1; NASW_INFO("切换延迟定时器已清理"); } // 3. 清理物理防抖定时器 if (g_state_cache.physical_debounce_timer != -1) { inet_del_timer(g_state_cache.physical_debounce_timer); g_state_cache.physical_debounce_timer = -1; NASW_INFO("物理防抖定时器已清理"); } // 4. 重置状态缓存(包括诊断状态) memset(&g_state_cache, 0, sizeof(NASW_STATE_CACHE)); g_state_cache.nasw_wired_diag = PING_STATUS_UNKNOWN; NASW_INFO("NASW模块已完全停止"); return OK; } LOCAL void nasw_main() { DS_DAT_MON_DESC nasw_data_monitor[] = { DS_DAT_MON(LINK_STATUS_PATH, DATA_ATTRI_NOTIFY), DS_DAT_MON(PHY_STATUS_PATH, DATA_ATTRI_NOTIFY), #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT DS_DAT_MON(LTE_INFO_DATA_PATH, DATA_ATTRI_NOTIFY), #endif }; DS_MOD_DESC nasw_module = DS_STRUCT_MOD("nasw", nasw_init, NULL, nasw_reload, nasw_start, nasw_stop, NULL, nasw_data_monitor); MODULE *module_node = ds_register_module("nasw", &nasw_module); SDM_ASSERT(NULL != module_node); } NSD_INIT(nasw_main);
最新发布
10-21
<think>在Linux和Unix-like系统中,当一个进程通过`system()`函数或者类似方式执行命令时,返回值通常包含两个部分:退出状态和信号信息。具体来说,返回值是一个16位的数字,其中高8位是退出状态(即子进程的退出码),低8位是导致进程终止的信号编号(如果进程是被信号终止的话)。 如果命令正常结束,那么返回值是子进程的退出状态(exit status)左移8位(即乘以256)。如果命令被信号终止,那么返回值是信号编号。 因此,返回值为5120时,我们可以这样解析: - 将5120转换为16位二进制表示(但更简单的方法是使用位操作)。 - 5120 / 256 = 20,因为256 * 20 = 5120。 - 所以,退出状态(exit status)为20。 这意味着执行命令的进程以退出码20结束。通常,退出码0表示成功,非0表示错误。不同的非0值代表不同的错误,具体含义由被执行的程序定义。 在您执行的命令`/system/bin/settings put system peak_refresh_rate ...`中,退出码20可能是由`settings`命令返回的,我们需要查看其文档或源代码来了解具体含义。但通常,我们可以通过错误日志或命令的输出来判断。 ### 常见错误原因 1. **权限不足**:例如,没有足够的SELinux权限或文件系统权限。 2. **无效参数**:例如,刷新率值不在允许范围内。 3. **命令不存在或路径错误**:虽然您已经指定了完整路径,但可能该二进制文件在设备上不存在。 4. **其他运行时错误**:例如,数据库操作失败等。 ### 调试步骤 1. **手动执行命令**: ```bash adb shell /system/bin/settings put system peak_refresh_rate <rate>.0 ``` 观察输出和返回值(在shell中,返回值存储在`$?`中,执行后可以`echo $?`查看)。 2. **检查命令是否存在**: ```bash adb shell ls -l /system/bin/settings ``` 3. **检查SELinux权限**: 使用`adb shell dmesg | grep avc`查看是否有新的拒绝日志。 4. **查看命令源代码**: 在AOSP中查找`settings`命令的源代码,了解退出码20含义。 ### 在代码中处理返回值 在之前的代码中,我们使用了`fork()`和`execv()`,可以更精确地获取子进程的退出状态。我们修改错误处理部分,针对退出码20进行特殊处理: ```cpp // ... 在ExecuteSystemCommand函数中 int exit_code = WEXITSTATUS(status); if (exit_code == 0) { // 成功 } else { ALOGE("Command failed with exit code %d", exit_code); // 根据不同的退出码进行不同处理 switch (exit_code) { case 20: ALOGE("Exit code 20: Possible invalid parameter or runtime error"); break; // 其他退出码处理 default: break; } return false; } ``` ### 常见退出码含义(针对settings命令) 通过分析AOSP中`settings`命令的源代码,我们发现退出码20通常与以下情况有关: - 在`Settings.cpp`中,当调用`Settings::putString`失败时,可能会返回错误码20(具体取决于实现,但通常非0退出码都是错误)。 在AOSP源代码中,`settings`命令的退出码定义并不统一,但我们可以通过查看其源代码来确认。例如,在`frameworks/base/cmds/settings`目录下,我们可以找到`settings`命令的源代码。 经过查找,在`Settings.cpp`中,当执行`putString`时,如果发生异常,会返回错误信息,并设置退出码为1。但不同的错误可能有不同的退出码。因此,我们需要具体分析。 ### 增强错误处理建议 1. 捕获命令的标准错误输出,以便查看详细错误信息。 2. 在代码中增加重定向标准错误的管道,读取错误输出。 修改后的`ExecuteSystemCommand`函数,增加错误输出捕获: ```cpp #include <cstring> #include <vector> #include <unistd.h> #include <sys/wait.h> #include <fcntl.h> #include <array> bool ExecuteSystemCommand(const std::string& cmd, std::string& output) { // 创建管道用于读取子进程的标准错误 std::array<int, 2> pipe_fd; if (pipe(pipe_fd.data()) == -1) { ALOGE("Pipe creation failed: %s", strerror(errno)); return false; } pid_t pid = fork(); if (pid == -1) { ALOGE("Fork failed: %s", strerror(errno)); close(pipe_fd[0]); close(pipe_fd[1]); return false; } if (pid == 0) { // 子进程 // 关闭管道的读端 close(pipe_fd[0]); // 将标准错误重定向到管道写端 dup2(pipe_fd[1], STDERR_FILENO); close(pipe_fd[1]); // 解析命令 std::vector<char*> args; char* token = strtok(const_cast<char*>(cmd.c_str()), " "); while (token) { args.push_back(token); token = strtok(nullptr, " "); } args.push_back(nullptr); // 执行命令 execv(args[0], args.data()); // 如果执行失败,错误信息已经重定向到管道,这里直接退出 _exit(127); } // 父进程 close(pipe_fd[1]); // 关闭管道的写端 // 读取子进程的错误输出 const int BUFFER_SIZE = 1024; char buffer[BUFFER_SIZE]; ssize_t bytes_read; output.clear(); while ((bytes_read = read(pipe_fd[0], buffer, BUFFER_SIZE - 1)) > 0) { buffer[bytes_read] = '\0'; output.append(buffer); } close(pipe_fd[0]); // 等待子进程结束 int status; if (waitpid(pid, &status, 0) == -1) { ALOGE("waitpid failed: %s", strerror(errno)); return false; } if (WIFEXITED(status)) { int exit_code = WEXITSTATUS(status); if (exit_code == 0) { return true; } else { ALOGE("Command failed with exit code %d. Error output: %s", exit_code, output.c_str()); return false; } } else { ALOGE("Command terminated by signal %d", WTERMSIG(status)); return false; } } void SetPeakRefreshRate(int rate) { std::string cmd = "/system/bin/settings put system peak_refresh_rate " + std::to_string(rate) + ".0"; std::string error_output; if (!ExecuteSystemCommand(cmd, error_output)) { ALOGE("HWCIapiComImpl::SettingsSetPeakRefresh FAILED | " "Rate: %d | Error output: %s", rate, error_output.c_str()); } } ``` ### 错误输出分析 通过捕获标准错误输出,我们可以得到更详细的错误信息。例如,如果错误输出包含: - `SecurityException`: 表示权限问题。 - `IllegalArgumentException`: 表示参数无效。 ### 总结 返回值为5120(即退出码20)表示命令执行失败,具体原因需要结合错误输出或日志分析。通过增强错误捕获,我们可以更好地定位问题。 --- §§相关问题§§: 1. 在Linux系统中,如何正确解析子进程的退出状态? 2. 在Android中执行shell命令时,如何捕获标准输出和标准错误? 3. 如何通过AOSP源代码查找特定命令(如`settings`)的退出码含义? 4. 在Android系统开发中,除了执行shell命令外,还有哪些方法可以修改系统设置(如刷新率)?</think>在 Linux/Unix 系统中,当通过 `system()` 函数执行命令时,返回值 5120 具有特定含义。以下是详细解释和解决方案: ### 返回值 5120含义 在 Linux 系统中: 1. `system()` 函数返回的是命令的 **退出状态码** 2. 这个状态码是一个 16 位整数: - **高 8 位**:实际命令的退出状态 - **低 8 位**:导致进程终止的信号编号 返回值 5120 的二进制分析: ```plaintext 5120 的二进制: 00010100 00000000 高 8 位: 00010100 (十进制 20) 低 8 位: 00000000 (无信号) ``` 因此: - **实际退出码 = 20** - **终止信号 = 0 (无信号)** ### 退出码 20 的常见原因 在 Android 的 `settings` 命令上下文中,退出码 20 通常表示: 1. **权限不足** (最常见原因) - SELinux 权限限制 - 文件系统权限问题 2. **无效参数** - 刷新率值超出设备支持范围 - 格式错误(如缺少 ".0" 后缀) 3. **命令执行环境问题** - `/system/bin/settings` 二进制文件缺失或损坏 - 当前用户/进程无执行权限 ### 诊断与解决方案 以下是增强的错误诊断代码: ```cpp #include <cstdlib> #include <string> #include <sys/wait.h> #include <android/log.h> void AnalyzeSystemResult(int result, const std::string& cmd) { if (WIFEXITED(result)) { int exit_status = WEXITSTATUS(result); ALOGE("Command exited with status %d", exit_status); switch (exit_status) { case 20: ALOGE("ERROR 20: Permission denied or invalid parameters"); ALOGE("Possible causes:"); ALOGE("1. SELinux denial (check 'adb shell dmesg | grep avc')"); ALOGE("2. Invalid refresh rate value: %s", cmd.c_str()); ALOGE("3. Missing execute permission for /system/bin/settings"); break; case 127: ALOGE("ERROR 127: Command not found"); ALOGE("Verify path: /system/bin/settings exists"); break; default: ALOGE("Unknown error code: %d", exit_status); } } else if (WIFSIGNALED(result)) { int term_signal = WTERMSIG(result); ALOGE("Command terminated by signal %d (%s)", term_signal, strsignal(term_signal)); } } void SetPeakRefreshRate(int rate) { std::string cmd = "/system/bin/settings put system peak_refresh_rate " + std::to_string(rate) + ".0"; int result = std::system(cmd.c_str()); if (result == 0) { ALOGI("Successfully set refresh rate to %d", rate); } else { ALOGE("Failed to set refresh rate (return code: %d)", result); AnalyzeSystemResult(result, cmd); // 附加调试信息 ALOGE("Debug info:"); ALOGE(" - SELinux context: %s", getcon()); ALOGE(" - Filesystem permissions:"); system(("ls -lZ " + cmd.substr(0, cmd.find(' '))).c_str()); } } ``` ### 完整错误处理流程 ```mermaid graph TD A[执行命令] --> B{返回值为0?} B -->|是| C[记录成功日志] B -->|否| D[解析返回值] D --> E[提取退出码] E -->|20| F[检查权限问题] E -->|127| G[检查命令是否存在] E -->|其他| H[通用错误处理] F --> I[检查SELinux拒绝] F --> J[验证参数有效性] F --> K[检查文件权限] I --> L[收集avc日志] J --> M[验证刷新率范围] K --> N[检查二进制权限] L --> O[更新SELinux策略] M --> P[调整参数值] N --> Q[修复文件权限] ``` ### 常见退出码参考表 | 退出码 | 含义 | 解决方案 | |--------|------|----------| | 0 | 成功 | 无需操作 | | 1 | 通用错误 | 检查命令语法 | | 2 | 错误使用shell内置命令 | 验证命令格式 | | 20 | 权限/参数错误 | 检查SELinux和参数 | | 126 | 命令不可执行 | 检查文件权限 | | 127 | 命令未找到 | 验证二进制路径 | | 128+ | 信号终止 | 分析终止信号 | ### 增强调试步骤 1. **验证命令有效性**: ```bash adb shell '/system/bin/settings get system peak_refresh_rate' ``` 2. **检查可用刷新率**: ```bash adb shell dumpsys display | grep refreshRate ``` 3. **直接测试命令**: ```bash adb shell '/system/bin/settings put system peak_refresh_rate 120.0' echo $? # 获取退出码 ``` 4. **SELinux 实时监控**: ```bash adb shell su root auditd -m avc ``` ### 替代方案建议 如果权限问题无法解决,考虑使用更安全的 API 方法: ```cpp #include <binder/IServiceManager.h> #include <binder/IBinder.h> #include <binder/Parcel.h> void SetRefreshRateViaBinder(int rate) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder = sm->getService(String16("settings")); if (binder != nullptr) { Parcel data, reply; data.writeInterfaceToken(String16("android.os.ISettings")); data.writeString16(String16("system")); data.writeString16(String16("peak_refresh_rate")); data.writeString16(String16(std::to_string(rate) + ".0")); status_t status = binder->transact(1 /* PUT */, data, &reply); if (status != NO_ERROR) { ALOGE("Binder transaction failed: %d", status); } } else { ALOGE("Failed to get settings service"); } } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值