ADD software version display

1. Problem Description

在手机拨号盘输入暗码*#xxx#,弹出对话框,显示手机各image版本号。

2. Analysis

已知条件:

  1. 手机各个分区版本已经写入到了工程源码的指定文件中(一般是放在development/version/include/version.inc文件中),其具体的形式如下所示:
  1. #define SCATTER_VER "K4H5EMMCCE00"
  2. #define PRELOADER_VER "P4H5H0H0CE00"
  3. #define UBOOT_VER "U4H5H0H0CE00"
  4. #define ANDROID_BOOT_VER "B4H5H0H0CE00"
  5. #define RECOVERY_VER "R4H5H0H0CE00"
  6. #define ANDROID_SYS_VER "Y4H5H0H0CE00"
  7. #define CACHE_VER "H4H5H0H0CE00"
  8. #define USRDATA_VER "S4H5H0H0CE00"
  9. #define LOGO_VER "L4H5H0H0CE00"
  10. #define FAT_VER "F4H5H0H0CE00"
  11. #define CUSTPACK_VER "C4H5HEU0CE00"
  12. #define SIMLOCK_VER "X4H0H0H0CE00"
  13. #define AP_DATABASE_VER "A4H5H0H0CE00"
  14. #define MODEM_DATABASE_VE "O4H5H0H0CE00"
  15. #define TRUSTZONE_VER "T4H5H0H0CE00"
  1. 输入暗码的dialog软件为第三方apk,该软件使用读系统属性的方法来获取版本信息,提供的系统属性接口如下:
  1. ro.tct.cust.ver /*保存custpack分区版本号的系统属性*/
  2. ro.tct.non.ver /*保存modem分区版本号的系统属性*/
  3. ro.tct.sys.ver /*保存system分区版本号的系统属性*/
  4. ro.tct.boot.ver /*保存boot分区版本号的系统属性*/
  5. ro.tct.preloader.ver /*保存preloader分区版本号的系统属性*/
  6. ro.tct.bootloader.ver /*保存bootloader分区版本号的系统属性*/
  7. ro.tct.reco.ver /*保存recovery分区版本号的系统属性*/

即当输入*#xxx#后,该apk会读取设备中的各个系统属性,然后将读到的值通过AlertDialog显示出来。

分析思路

既然已经知道了各个分区版本号所存储的文件位置,又知道三方apk读取信息的接口,那么需要做的就是:

  1. 读取文件version.inc中的数据;
  2. 将读到的值存入到对应的系统属性中;

问题似乎已经得到了解决,但是system、boot、preloader、bootloader、recovery分区的版本号在fota版本升级后会变化。也就是说通过上面的做法,将编译好的系统刷如设备中,该设备的各个分区版本号是永远不能改变的,那么上面的做法就无法满足版本升级后部分分区版本号改变的要求了。

因此,可以分为2种不同情况来处理,具体如下图所示:

  • 对于在fota升级前后不需要改变的版本号,直接读取该版本号,然后将它写入对应系统属性中。

  • 对于在fota升级前后需要改变的版本号,首先,将它读取出来写入到一个中间文件(对于boot和system版本号是存放.ver文件中,其他三个的版本号是放在对应的.img文件中特定位置并且加有标识字符)中,;然后,在手机每次启动时,动态的读取这个中间文件的值,并将读到的值写入对应系统属性中;如果有fota升级,在升级时会同时替换升级分区的中间文件,这样就可以保证每次显示版本号时,都是读取的最新版本号。

3. Solution

3.1 处理升级前后不改变的版本号

  1. 修改/build/core/Makefile文件

    从文件development/version/include/version.inc中分别读取modem分区版本号和custpack分区版本号,然后写入系统属性中,具体代码如下:
  1. VERSIONDEF := development/version/include/version.inc #引进version.inc文件
  2. VERSIONLEN := 12
  3. CUSTPACK_VER := $(shell awk ' /CUSTPACK_VER/ { print substr($$NF, 2,$(VERSIONLEN) ) }' $(TOPDIR)$(VERSIONDEF))
  4. MODEM_DATABASE_VE := $(shell awk ' /MODEM_DATABASE_VE/ { print substr($$NF, 2,$(VERSIONLEN) ) }' $(TOPDIR)$(VERSIONDEF))
  5. $(hide) TARGET_BUILD_TYPE="$(TARGET_BUILD_VARIANT)"
  6. ......
  7. CUSTPACK_VER="$(CUSTPACK_VER)" \
  8. MODEM_DATABASE_VE="$(MODEM_DATABASE_VE)" \
  9. ......
  1. 修改文件build/tools/buildinfo.sh
  1. echo "ro.tct.cust.ver=$CUSTPACK_VER"
  2. echo "ro.tct.non.ver=$MODEM_DATABASE_VE“

到现在modem分区版本号和custpack分区版本号已经写入到文件out目录下build.prop文件中,通过打开该文件可以看到从version.inc中读到的版本号。

3.2 处理升级前后改变的版本号

  • 修改/build/core/Makefile文件
  1. #write boot version to boot.ver
  2. if [ -f $(TOPDIR)$(VERSIONDEF) ];#将boot分区版本号写入到临时文件boot.ver中
  3. then
  4. awk ' /ANDROID_BOOT_VER/ { print substr($$NF, 2, $(VERSIONLEN)) }' $(TOPDIR)$(VERSIONDEF) > $(TARGET_ROOT_OUT)/boot.ver ;
  5. fi
  6. #write boot version to boot.ver
  7. ......
  8. define build-systemimage-target
  9. #write system version to system.ver
  10. if [ -f $(TOPDIR)$(VERSIONDEF) ];#将system分区版本号写入到临时文件boot.ver中
  11. then
  12. awk ' /ANDROID_SYS_VER/ { print substr($$NF, 2,$(VERSIONLEN)) }' $(TOPDIR)$(VERSIONDEF) > $(TARGET_OUT)/system.ver;
  13. fi
  14. #write system version to system.ver
  15. #write recovery version and the string of JRD_VERSION_MARK_ to recovery.img
  16. RECOVER_VERSION = JRD_VERSION_MARK_$(shell awk ' /RECOVERY_VER/ { print substr($$NF, 2,$(VERSIONLEN) ) }' $(TOPDIR)$(VERSIONDEF))
  17. # Assumes this has already been stripped
  18. ifdef BOARD_KERNEL_CMDLINE
  19. INTERNAL_RECOVERYIMAGE_ARGS += --cmdline "$(BOARD_KERNEL_CMDLINE) $(RECOVER_VERSION)"
  20. else
  21. INTERNAL_RECOVERYIMAGE_ARGS += --cmdline "$(RECOVER_VERSION)"
  22. Endif
  23. #write recovery version and the string of JRD_VERSION_MARK_ to recovery.img
  • 修改文件/vendor/mediatek/proprietary/bootable/bootloader/lk/Android.mk在指定头文件中定义一个宏定义,编译后再打开该version.h文件,可以看到如#define LK_VER JRD_VERSION_MARK_U4HB3004CE00样子的宏定义。
  1. VERSIONDEF := development/version/include/version.inc
  2. VERSIONLEN := 12
  3. if [ -f $(LK_ROOT_DIR)/$(VERSIONDEF) ];
  4. then
  5. echo -n "#define LK_VER JRD_VERSION_MARK_" > $(LK_ROOT_DIR)/vendor/mediatek/proprietary/bootable/bootloader/lk/include/version.h ;
  6. awk ' /UBOOT_VER/ { print substr($$NF, 2, $(VERSIONLEN)) }' $(LK_ROOT_DIR)/$(VERSIONDEF) >> $(LK_ROOT_DIR)/vendor/mediatek/proprietary/bootable/bootloader/lk/include/version.h ;
  7. fi
  • 修改文件vendor/mediatek/proprietary/bootable/bootloader/lk/kernel/main.c,将前面的宏定义LK_VER写入到对应的.img文件中去。
  1. #include "version.h"
  2. ststatic int bootstrap2(void *arg)
  3. {
  4. ......
  5. #ifdef LK_VER
  6. #define xstr(s) str(s)
  7. #define str(s) #s
  8. printf("%s\n", xstr(LK_VER));/*大概是只要使用了该宏,就会为该宏分配存储空间并存储在目标文件img中*/
  9. #endif
  10. ......
  11. }
  • 修改文件vendor/mediatek/proprietary/bootable/bootloader/preloader/Android.mk在指定头文件中定义一个宏定义,编译后再打开该version.h文件,可以看到如#define PRELOADER_VER JRD_VERSION_MARK_P4HB3004CE00样子的宏定义。
  1. VERSIONDEF := development/version/include/version.inc
  2. VERSIONLEN := 12
  3. if [ -f $(PRELOADER_ROOT_DIR)/$(VERSIONDEF) ];
  4. then
  5. echo -n "#define PRELOADER_VER JRD_VERSION_MARK_" > $(PRELOADER_DIR)/platform/mt6735/src/core/inc/version.h ;
  6. awk ' /PRELOADER_VER/ { print substr($$NF, 2, $(VERSIONLEN)) }' $(PRELOADER_ROOT_DIR)/$(VERSIONDEF) >> $(PRELOADER_DIR)/platform/mt6735/src/core/inc/version.h ;
  7. fi
  • 修改文件vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6735/src/core/main.c,将前面的宏定义PRELOADER_VER写入到对应的.img文件中去。
  1. #include "version.h"
  2. static void bldr_pre_process(void)
  3. {
  4. ......
  5. #ifdef PRELOADER_VER
  6. #define xstr(s) str(s)
  7. #define str(s) #s
  8. printf("%s\n", xstr(PRELOADER_VER));
  9. #endif
  10. ......
  11. }
  • 修改文件vendor/jrdcom/proprietary/traceability/main.c,将.ver文件中的版本号读取出来,然后写入相应的系统属性.ro中
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <errno.h>
  4. #include <stdlib.h>
  5. #include <sys/types.h>
  6. #include <fcntl.h>
  7. #include <unistd.h>
  8. #define __ALLOCATE_CFG_AUDIO_DEFAULT_H
  9. #include "libnvram.h"
  10. #include "CFG_PRODUCT_INFO_File.h"
  11. #include "Custom_NvRam_LID.h"
  12. #include <cutils/properties.h>
  13. //#define printf(x...) do { KLOG_ERROR("!!!!!!!!!!!!!!", x); } while (0)
  14. #include <android/log.h>
  15. #define LOG_TAG "gettra"
  16. #define printf(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
  17. //VERSION parameter
  18. #define VERSION_FILE_PATCH "/system/system.ver"
  19. #define VERSION_OFFSET 0
  20. #define VERSION_SIZE 12
  21. #define VERSION_ANBOOT_FILE_PATCH "/boot.ver"
  22. int main(int argc, char *argv[])
  23. {
  24. int fid_ver;
  25. unsigned char ver[13]={0};
  26. unsigned char anbootver[13]={0};
  27. int fid_anbootver;
  28. memset(ver, 0x00, 12);
  29. memset(anbootver, 0x00, 12);
  30. //get version and set ro.tct.sys.ver
  31. fid_ver = open( VERSION_FILE_PATCH, O_RDONLY);
  32. if(fid_ver < 0)
  33. {
  34. perror("open:error");
  35. }
  36. else
  37. {
  38. lseek(fid_ver, VERSION_OFFSET , SEEK_SET);
  39. read(fid_ver, ver, VERSION_SIZE);
  40. close(fid_ver);
  41. }
  42. fid_anbootver = open( VERSION_ANBOOT_FILE_PATCH, O_RDONLY);
  43. if(fid_anbootver < 0)
  44. {
  45. //perror("open:error");
  46. printf("fid_anbootver error\n");
  47. }
  48. else
  49. {
  50. printf("fid_anbootver \n");
  51. lseek(fid_anbootver, VERSION_OFFSET , SEEK_SET);
  52. read(fid_anbootver, anbootver, VERSION_SIZE);
  53. close(fid_anbootver);
  54. }
  55. property_set("ro.tct.sys.ver", ver);
  56. property_set("ro.tct.boot.ver", anbootver);
  57. printf("gettracability exe over!\n");
  58. return 1;
  59. }
  60. #undef __ALLOCATE_CFG_AUDIO_DEFAULT_H
  • 修改文件vendor/jrdcom/proprietary/version/main.c,将.img文件中的版本号读取出来,然后写入相应的系统属性.ro中
  1. /*
  2. * Get version number from raw partition image, output to one file.
  3. */
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <fcntl.h>
  10. #include <unistd.h>
  11. #include <sys/system_properties.h>
  12. #include <utils/Log.h>
  13. #define printf ALOGE
  14. #define PRELOADER "/dev/block/mmcblk0boot0"
  15. #define BOOTLOADER "/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/lk"
  16. #define RECOVERYIMG "/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/recovery"
  17. #define PRELOADER_SIZE 0x40000
  18. #define BOOTLOADER_SIZE 0x60000
  19. #define RECOVERYIMG_SIZE 0x900000
  20. #define JRD_VERSION_MARK "JRD_VERSION_MARK_"
  21. #define JRD_VERSION_MARK_LEN 17
  22. #define JRD_VERSION_LEN 12
  23. static char buff[RECOVERYIMG_SIZE];
  24. /*这个方法就是先从指定img文件中读size个字节到一个临时数组ver中,然后根据size的大小,将数组中的值存入相应的系统属性.ro文件中*/
  25. int getver(char *img, int size)
  26. {
  27. int ret = 0;
  28. char ver[JRD_VERSION_MARK_LEN + JRD_VERSION_LEN + 1];
  29. char setver[JRD_VERSION_MARK_LEN + JRD_VERSION_LEN + 1]={'\0'};
  30. int f;
  31. ssize_t s;
  32. int p;
  33. /*为数组分配存储空间大小为 17+12+1*/
  34. memset(ver, 0, JRD_VERSION_MARK_LEN);
  35. /*先讲表示字段"JRD_VERSION_MARK_"拷贝到数组中*/
  36. strncpy(ver, JRD_VERSION_MARK, JRD_VERSION_MARK_LEN);
  37. // read image
  38. f = open(img, O_RDONLY);
  39. if (f < 0) {
  40. printf("can not open image!!!!!!!!!!!!!!!!!!\n");
  41. return f;
  42. }
  43. /*将.img文件中的前size个字符拷贝到buff中*/
  44. s = read(f, buff, size);
  45. printf("read out byte cnt: %d!!!!!!!!!!!!!!!!!!\n", s);
  46. f = close(f);
  47. // search the mark string
  48. for(p = 0; p < size; p++) {
  49. // match the first char
  50. if (buff[p] == ver[0]) {
  51. int t;
  52. for(t = 0; t < JRD_VERSION_MARK_LEN; t++) {
  53. if(buff[p + t] != ver[t])
  54. break;
  55. }
  56. // match whole mark string
  57. if(t == JRD_VERSION_MARK_LEN)
  58. break;
  59. }
  60. }
  61. // not find
  62. if (p == size)
  63. return ret;
  64. /*p + strlen(JRD_VERSION_MARK)为版本号在buff中的偏移位*/
  65. // find it
  66. strncpy(ver, buff + p + strlen(JRD_VERSION_MARK), JRD_VERSION_LEN);
  67. ver[JRD_VERSION_LEN] = '\n';
  68. if(size == PRELOADER_SIZE)
  69. {
  70. strncpy(setver,ver, JRD_VERSION_LEN);
  71. setver[JRD_VERSION_LEN] = '\0';、
  72. /*将版本号写入系统属性ro.tct.preloader.ver中*/
  73. if(property_set("ro.tct.preloader.ver", setver) <0)
  74. {
  75. printf("can not set ro.tct.preloader.ver!!!!!!!!!!!!!!!\n");
  76. }
  77. }else if (size == BOOTLOADER_SIZE){
  78. strncpy(setver,ver, JRD_VERSION_LEN);
  79. setver[JRD_VERSION_LEN] = '\0';
  80. /*将版本号写入系统属性ro.tct.bootloader.ver中*/
  81. if(property_set("ro.tct.bootloader.ver", setver) <0)
  82. {
  83. printf("can not set ro.tct.bootloader.ver!!!!!!!!!!!!!!!\n");
  84. }
  85. }else{
  86. strncpy(setver,ver, JRD_VERSION_LEN);
  87. setver[JRD_VERSION_LEN] = '\0';
  88. /*将版本号写入系统属性ro.tct.reco.ver中*/
  89. if(property_set("ro.tct.reco.ver", setver) <0)
  90. {
  91. printf("can not set ro.tct.reco.ver!!!!!!!!!!!!!!!\n");
  92. }
  93. }
  94. return ret;
  95. }
  96. int main(int argc, char *argv[])
  97. {
  98. int ret = 0;
  99. printf("PRELOADER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
  100. ret = getver(PRELOADER, PRELOADER_SIZE);
  101. printf("BOOTLOADER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
  102. ret = getver(BOOTLOADER, BOOTLOADER_SIZE);
  103. printf("RECOVERYIMG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
  104. ret = getver(RECOVERYIMG, RECOVERYIMG_SIZE);
  105. return ret;
  106. }

到现在基本改完了,然后编译系统并将编好系统刷入设备中,验证发现无法显示出所有的版本号。难到上面的分析有问题?通过log分析发现,问题出在SELinux权限的方面。那什么是SELinux呢?说简单点,就是针对某个进程,它是否具有访问某个文件资源的权限。而在上面运行vendor/jrdcom/proprietary/version/main.c代码的进程需要访问lk、preloader、recovery这个3个分区的文件资源。我们需要将该进程读这3个分区的权限放开,才能获得分区中的版本号,不然无法获取版本号的值。

需要注意的是要具体查看项目中到底使用到哪个目录下的sepolicy规则,可以通过查看BoardConfig.mk文件来确定

  1. #SELinux Policy File Configuration
  2. ifeq ($(strip $(MTK_BASIC_PACKAGE)), yes)
  3. BOARD_SEPOLICY_DIRS += \
  4. device/mediatek/mt6735/sepolicy/basic
  5. endif
  6. ifeq ($(strip $(MTK_BSP_PACKAGE)), yes)
  7. BOARD_SEPOLICY_DIRS += \
  8. device/mediatek/mt6735/sepolicy/basic \
  9. device/mediatek/mt6735/sepolicy/bsp
  10. endif
  11. ifneq ($(strip $(MTK_BASIC_PACKAGE)), yes)
  12. ifneq ($(strip $(MTK_BSP_PACKAGE)), yes)
  13. BOARD_SEPOLICY_DIRS += \
  14. device/mediatek/mt6735/sepolicy/basic \
  15. device/mediatek/mt6735/sepolicy/bsp \
  16. device/mediatek/mt6735/sepolicy/full
  17. endif
  18. endif

具体的selinux规则修改如下:

  • 在文件[sepolicy规则目录]/file.te中定义一个type,具体如下:
  1. type getver_data_file, file_type;
  • 在文件[sepolicy规则目录]/device.te中定义一个type,具体如下:
  1. type lk_block_device, dev_type;
  • 在文件[sepolicy规则目录]/file_contexts中定义定义文件的安全上下文,具体如下:
  1. #lk文件的安全上下文
  2. /dev/block/platform/mtk-msdc\.0/[0-9]+\.msdc0/by-name/lk u:object_r:lk_block_device:s0
  3. #getver文件的安全上下文
  4. /system/bin/getver u:object_r:getver_exec:s0
  5. /data/imgver u:object_r:getver_data_file:s0
  • 在文件[sepolicy规则目录]下创建一个getver.te文件,具体如下:
  1. # getver
  2. #为getver应用定义域
  3. type getver, domain;
  4. #定义一个getver_exec类型的type
  5. type getver_exec, exec_type, file_type;
  6. init_daemon_domain(getver)
  7. # Give getver a place where only getver can store files; everyone else is off limits
  8. file_type_auto_trans(getver, system_data_file, getver_data_file)
  9. #定义getver应用对文件的访问规则
  10. allow getver getver_data_file:file {create rw_file_perms};
  11. allow getver block_device:file {open rw_file_perms};
  12. allow getver block_device:dir {search rw_file_perms};
  13. allow getver nvram_data_file:file {open rw_file_perms};
  14. allow getver nvram_data_file:lnk_file {r_file_perms};
  15. allow getver nvram_data_file:dir {search r_file_perms};
  16. allow getver nvdata_file:dir {search rw_file_perms};
  17. allow getver userdata_block_device:blk_file {rw_file_perms};
  18. allow getver preloader_block_device:blk_file {r_file_perms};
  19. allow getver recovery_block_device:blk_file {r_file_perms};
  20. allow getver lk_block_device:blk_file {open r_file_perms};
  21. #allow getver system_data_file:dir {create search rw_file_perms add_name};
  22. allow getver getver_data_file:file {create open read write};
  23. #added by xuanfeng.ye for Task1304435 begin
  24. allow getver system_file:file {execute_no_trans};
  25. #added by xuanfeng.ye for Task1304435 end
  26. #20170204-jrdhz-yaosen.lin-add-for-t3695219-to-show version-brand
  27. allow getver property_socket:sock_file { write };
  28. allow getver system_prop:property_service { set };
  29. allow getver init:unix_stream_socket { connectto };

经过上面的修改,运行vendor/jrdcom/proprietary/version/main.c代码的进程就可以读取img文件中的版本号,并且将版本号写入对应的系统属性中了。而三方dialog apk就可以通过读取对应的系统属性来在界面上显示各个版本号了,对于系统属性读写需不需要加selinux访问规则就要看项目具体的配置了,如果项目对系统属性也使用了selinux,则要对系统属性加上对应selinux规则才能正确显示版本号。

4. Summary

这做这个defect的时候,需要区分软件升级前后要改变的版本号和不需要改变的版本号,对应升级前后一直不变的版本号,只需要将它们读出来,静态的写入到文件中,在需要使用的时候再拿出来就可以了。而对应升级前后需要改变的版本号,可以通过中间文件的形式来处理即在每次开机的时候通过读取中间文件来获取版本号,同时在软件升级时候同时更新中间文件来确保版本号也一起更新过,而在做这个问题的时候,遇到的难点则是selinux部分,因为对selinux的知识也不是很熟悉,写的selinux规则也是照猫画虎将别人的搬过来,而没有实际理解它们的含义,所以导致编译N次都没有成功的读取出img部分的版本号。整个问题的解决思路还是比较简单的,特别需要的就是各个地方的细节,比如最开始写的selinux规则,不管怎么写都没有效果,最后发现原来是使用的那个sepolicy目录根据就没有编译进系统。

ADD software version display的更多相关文章

  1. cordova platform add specified version

    cordova platform add specified version 命令格式 cordova platform add android@4.0 可用的版本 Valid install tar ...

  2. 【转】System.Data.OracleClient requires Oracle client software version 8.1.7 or greater

    安装完ASP.NET,Oracle9i客户端后,使用System.Data.OracleClient访问Oracle数据库如果出现这种错误:System.Data.OracleClient requi ...

  3. Software Version

    Software Version Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) To ...

  4. C# System.Data.OracleClient requires Oracle client software version 8.1.7 or greater

    好好的程序,突然出现了错误,原因是:System.Data.OracleClient requires Oracle client software version 8.1.7 or greater, ...

  5. Eclipse执行import命令导入maven项目时报错:Add a version or custom suffix using "Name template" in "Advanced" settings

    新建了两个maven项目在E盘workspace目录,后面移到workspace/app_engine目录下提交svn,再通过Eclipse的File->import导入时报错了: Projec ...

  6. Data Base System.Data.OracleClient requires Oracle client software version 8.1.7 or greater解决方案

    System.Data.OracleClient requires Oracle client software version 8.1.7 or greater解决方案 一.问题: 1.通过Syst ...

  7. System.Data.OracleClient requires Oracle client software version 8.1.7 or greater

    It is a security issue, so to fix it simply do the following: Go to the Oracle folder. 1- Right Clic ...

  8. HDOJ(HDU) 1976 Software Version(简单判断)

    Problem Description 相信大家一定有过在网上下载软件而碰到多个不同版本的情况. 一般来说,软件的版本号由三个部分组成,主版本号(Major Version Number),子版本号( ...

  9. Software Version --hdu1976

    #include using namespace std; int main() { int T; cin>>T; int a1,b1,c1; int a2,b2,c2; while(T- ...

随机推荐

  1. [BUUCTF]PWN——[Black Watch 入群题]PWN

    [Black Watch 入群题]PWN--栈劫持 入群题密码在 /password.txt Ubuntu 16 2020年02月27日:此入群题已作废,请看新版入群题. 附件 解题步骤: 例行检查, ...

  2. RabbitMQ,RocketMQ,Kafka 消息模型对比分析

    消息模型 消息队列的演进 消息队列模型 发布订阅模型 RabbitMQ的消息模型 交换器的类型 direct topic fanout headers Kafka的消息模型 RocketMQ的消息模型 ...

  3. [源码解析] PyTorch 分布式之弹性训练(1) --- 总体思路

    [源码解析] PyTorch 分布式之弹性训练(1) --- 总体思路 目录 [源码解析] PyTorch 分布式之弹性训练(1) --- 总体思路 0x00 摘要 0x01 痛点 0x02 难点 0 ...

  4. LuoguP6553 Strings of Monody 题解

    Content 给定一个长度为 \(n\) 的字符串 \(s\)(仅包含 \(1,4,5\) 三种字符,\(n\) 在本题中无需输入),有 \(m\) 个操作,每次操作给定两个整数 \(l,r\),再 ...

  5. Linux的课堂便利脚本

    上课的时,因为教室机总会重新重启,有时候就要重配网卡yum源和下载一些辅助工具,这里写一个脚本省去冗杂的过程 if [[]]可以防止unary operator expected的报错 nmcli d ...

  6. RenderFlex children have non-zero flex but incoming height constraints are unbounded.

    问题 Flexible 里用了 Column, 使得高度无法确定 解决方案 将Flexible替换为ConstrainedBox, 并设定maxHeight 代码 ConstrainedBox( co ...

  7. 【剑指Offer】不用加减乘除做加法 解题报告(Java)

    [剑指Offer]不用加减乘除做加法 解题报告(Java) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-interviews 题 ...

  8. git 上传项目到远程仓库

    电脑安装git客户端.注册github账号并登陆 到本地项目文件夹右键选择git bash here 输入个人信息(代码提交者) git config --global user.name " ...

  9. Chapter 14 G-estimation of Structural Nested Models

    目录 14.1 The causal question revisited 14.2 Exchangeability revisited 14.3 Structural nested mean mod ...

  10. Reliable evaluation of adversarial robustness with an ensemble of diverse parameter-free attacks

    目录 概 主要内容 Auto-PGD Momentum Step Size 损失函数 AutoAttack Croce F. & Hein M. Reliable evaluation of ...