当前位置: 首页 > 编程日记 > 正文

Android5.0如何正确启用isLoggable(二) 理分析

转自:http://www.it165.net/pro/html/201506/43374.html


概要

在上文《Android 5.0 如何正确启用isLoggable(一)__使用详解》中分析了isLoggable的使用方法,本文主要分析isLoggable实现原理以及user版系统root后永久enable isLoggable的原理,并使用脚本自动设置isLoggable相关属性。

本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处

isLoggable工作原理

isLoggable定义在frameworks/base/core/java/android/util/Log.java中:

view sourceprint?
01./**
02.* Checks to see whether or not a log for the specified tag is loggable at the specified level.
03.*
04.*  The default level of any tag is set to INFO. This means that any level above and including
05.*  INFO will be logged. Before you make any calls to a logging method you should check to see
06.*  if your tag should be logged. You can change the default level by setting a system property:
07.*      'setprop log.tag.<YOUR_LOG_TAG> <LEVEL>'
08.*  Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPPRESS will
09.*  turn off all logging for your tag. You can also create a local.prop file that with the
10.*  following in it:
11.*      'log.tag.<YOUR_LOG_TAG>=<LEVEL>'
12.*  and place that in /data/local.prop.
13.*
14.* @param tag The tag to check.
15.* @param level The level to check.
16.* @return Whether or not that this is allowed to be logged.
17.* @throws IllegalArgumentException is thrown if the tag.length() > 23.
18.*/
19.public static native boolean isLoggable(String tag, int level);

而isLoggable的native实现则是在frameworks/base/core/jni/android_util_Log.cpp中:

view sourceprint?
01.static JNINativeMethod gMethods[] = {
02./* name, signature, funcPtr */
03."isLoggable",      "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
04."println_native",  "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
05.};
06. 
07.static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
08.{
09.//... ...省略
10.jboolean result = false;
11.if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) {
12.char buf2[200];
13.snprintf(buf2, sizeof(buf2), "Log tag "%s" exceeds limit of %zu characters
14.",
15.chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE));
16.jniThrowException(env, "java/lang/IllegalArgumentException", buf2);
17.else {
18.// 调用本地isLoggalbe方法
19.result = isLoggable(chars, level);
20.}
21.env->ReleaseStringUTFChars(tag, chars);
22.return result;
23.}

从代码中可以看到,android_util_Log_isLoggable()的返回值取决于android_util_Log.cpp中的isLoggable()方法:

view sourceprint?
01.#define LOG_NAMESPACE "log.tag."
02.static jboolean isLoggable(const char* tag, jint level) {
03.String8 key;
04.key.append(LOG_NAMESPACE);
05.key.append(tag);
06. 
07.char buf[PROPERTY_VALUE_MAX];
08.//获取属性log.tag.<Your_TAG>的值
09.if (property_get(key.string(), buf, "") <= 0) {
10.buf[0] = '';
11.}
12.int logLevel = toLevel(buf);
13.return logLevel >= 0 && level >= logLevel;
14.}

在android_util_Log.cpp中的isLoggable()首先会通过property_get()去获取log.tag.<Your_TAG>的属性值,如果没有设置该属性则将buf[0]设为空,再通过toLevel()方法获取logLevel的值,最终返回值由logLevel >= 0 && level >=logLevel决定。toLevel()方法内容如下:

view sourceprint?
01.static int toLevel(const char* value)
02.{
03.switch (value[0]) {
04.case 'V'return levels.verbose;
05.case 'D'return levels.debug;
06.case 'I'return levels.info;
07.case 'W'return levels.warn;
08.case 'E'return levels.error;
09.case 'A'return levels.assert;
10.case 'S'return -1// SUPPRESS
11.}
12.return levels.info;
13.}

levels是结构体levels_t的对象,在register_android_util_Log()方法完成赋值,而register_android_util_Log()方法则是在系统启动时通过AndroidRuntime.cpp中的REG_JNI(register_android_util_Log)完成调用,代码如下:

view sourceprint?
01.struct levels_t {
02.jint verbose;
03.jint debug;
04.jint info;
05.jint warn;
06.jint error;
07.jint assert;
08.};
09.static levels_t levels;
10. 
11.int register_android_util_Log(JNIEnv* env)
12.{
13.jclass clazz = FindClassOrDie(env, "android/util/Log");
14.//获取android.util.Log中VERBOSE/DEBUG/INFO/WARN/ERROR/ASSERT的值,并赋给levels
15.levels.verbose = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "VERBOSE""I"));
16.levels.debug = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "DEBUG""I"));
17.levels.info = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "INFO""I"));
18.levels.warn = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "WARN""I"));
19.levels.error = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ERROR""I"));
20.levels.assert = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ASSERT""I"));
21.return RegisterMethodsOrDie(env, "android/util/Log", gMethods, NELEM(gMethods));
22.}

在toLevel()方法中,如果字符数组value[0]匹配V/D/I/W/E/A/S则返回对应的Int值,如果value[0]为空,则返回默认值levels.info即4。再次回看android_util_Log.cpp中的isLoggable()方法:

view sourceprint?
1.static jboolean isLoggable(const char* tag, jint level) {
2.//... ...省略
3.int logLevel = toLevel(buf);
4.return logLevel >= 0 && level >= logLevel;
5.}

因为levels结构体中数据均来自android.util.Log中,最小值为2 ( VERBOSE ),最大值为7 ( ASSERT ),因此 logLevel >=0 始终为true。而level >=logLevel则会根据用户指定的level进行判断,如

view sourceprint?
1.android.util.Log.isLoggable("InCall", android.util.Log.DEBUG);

这里的level是DEBUG也就是3,相当于 level >= logLevel变为3 >= logLevel。如果没有设置属性值log.tag.InCall的值,则logLevel的默认返回为4 ( INFO),因此 3 >= 4不成立返回false,因此logLevel >=0 && level >= logLevel返回false;如果设置log.tag.InCall的值为D或者V,则logLevel返回为 3或者2,因此level >= logLevel成立,从而使得isLoggable返回为true。

Android Property System简介

在isLoggable的调用流程中涉及到属性值的读取,这里简单了解Android Property System的工作流程。如下图所示:

图 1 android property system (Pic From @rxwen)

蓝色表示独立进程,橙色表示共享内存,白色表示属性文件。属性值的获取通过property consumer完成,当系统启动时会将persistent file中的属性值加载到共享内存中,如果需要设置属性值,那么property setter会通过socket将需求提交给property service,由property service将属性值写入到共享内存中。

因为设置属性如log.tag.InCall D后会写入到共享内存中,但设备重启后会重新申请共享内存并加载属性文件,而手动设置的属性并没有写入属性文件,所以重启设备后log.tag.InCall的属性会失效。

local .prop文件加载流程

在前文《Android 5.0 如何正确启用isLoggable(一)__使用详解》中提到,如果想要重启后设置的log.tag.<Your_Tag>属性依然有效,那么需要将log.tag.InCall=D写入/data/local.prop文件中,重启设备后系统会加载该路径下的属性文件。那这一步是如何完成的呢?这就涉及到Android Property System的初始化流程。

Android Property Service是在Init进程中被初始化的,而在初始化过程中会加载指定路径下的属性文件,加载流程如下图所示:

图 2 Property files init flow

图中涉及文件路径:

/system/core/init/init.cpp

/system/core/init/init_parser.cpp

/system/core/init/builtins.cpp

/system/core/init/property_service.cpp

/system/core/rootdir/init.rc

init进程启动后首先执行main()方法,之后通过init_parse_config_file()加载init.rc文件,并对init.rc文件进行解析,最后将解析出来的service、action及其command存入链表中。在完成init.rc解析之后通过execute_one_command()方法,逐个取出链表中的command并执行。init.rc中的properties相关action如下:

view sourceprint?
1.# Load properties from /system/ + /factory after fs mount.
2.on load_all_props_action
3.load_all_props
4.start logd-reinit

load_all_props的定义在/system/core/init/keywords.h中:

view sourceprint?
01.#ifndef KEYWORD
02.//... ...
03.#define __MAKE_KEYWORD_ENUM__
04.#define KEYWORD(symbol, flags, nargs, func) K_##symbol,
05.enum {
06.K_UNKNOWN,
07.#endif
08.//... ...
09.KEYWORD(load_persist_props,    COMMAND, 0, do_load_persist_props)
10.KEYWORD(load_all_props,        COMMAND, 0, do_load_all_props)
11.//... ...
12.#ifdef __MAKE_KEYWORD_ENUM__
13.KEYWORD_COUNT,
14.};
15.#undef __MAKE_KEYWORD_ENUM__
16.#undef KEYWORD
17.#endif

最终调用到/system/core/init/property_service.cpp的load_all_props()方法中:

view sourceprint?
01.void load_all_props() {
02.load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
03.load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
04.load_properties_from_file(PROP_PATH_BOOTIMAGE_BUILD, NULL);
05.load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
06. 
07.load_override_properties();
08. 
09./* Read persistent properties after all default values have been loaded. */
10.load_persistent_properties();
11.}

展开load_override_properties()方法可以看到:

view sourceprint?
01.static void load_override_properties() {
02.if (ALLOW_LOCAL_PROP_OVERRIDE) {
03.char debuggable[PROP_VALUE_MAX];
04.int ret = property_get("ro.debuggable", debuggable);
05.if (ret && (strcmp(debuggable, "1") == 0)) {
06.load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL);
07.}
08.}
09.}

通过load_properties_from_file()以及load_override_properties()等方法加载属性文件,这些文件的路径定义在/bionic/libc/include/sys/_system_properties.h中:

view sourceprint?
1.#define PROP_PATH_RAMDISK_DEFAULT  "/default.prop"
2.#define PROP_PATH_SYSTEM_BUILD     "/system/build.prop"
3.#define PROP_PATH_VENDOR_BUILD     "/vendor/build.prop"
4.#define PROP_PATH_LOCAL_OVERRIDE   "/data/local.prop"
5.#define PROP_PATH_FACTORY          "/factory/factory.prop"

但这里需要注意,/system/build.prop、/vendor/build.prop、/factory/factory.prop这几个文件如果存在都会被加载,而/data/local.prop这个文件,只有在ro.debuggable=1时才会加载,也就是说/data/local.prop只有在userdebug/eng的情况下,才会被系统加载。

user版系统永久开启isLoggable原理

在前文《Android 5.0 如何正确启用isLoggable(一)__使用详解》中,已给出使能isLoggable的方法以及各种方法间的优劣对比。其中,如果当前设备是user版,但在获取root权限之后能够永久开启isLoggable。通过前面的分析可以知道,在user版系统中,/data/local.prop属性文件是不会被property service读取的,但/system/build.prop属性文件无论user还是userdebug/eng版本都会读取,因此直接将log.tag.<Your_Tag>追加到/system/build.prop文件中即可。

也可以使用以下脚本(Windows)设置isLoggable的属性值( 需要adbd获取root权限即能够使用adb remount ):

view sourceprint?
01.@echo off
02.echo ============= Open Hidden Logs =============
03.echo =============   version 0.2  =============
04.echo =============     20150605   =============
05.echo =============      SEVEN     =============
06. 
07.REM Update:
08.REM 1. Rename the script to OpenHiddenLogs.bat.
09.REM 2. Adaptation of user mode device.
10.REM 3. Add the instructions and steps.
11. 
12.REM Instructions:
13.REM This script is used to enable some hide logs in Android Platforms.
14.REM Android property system provides an approach to enable isLoggable(String tag, int level).
15.REM You'll find some code in Android as below:
16.REM private static final String TAG = "Telecom";
17.REM public static final boolean DEBUG = android.util.Log.isLoggable(TAG, android.util.Log.DEBUG);
18.REM if (DEBUG) {
19.REM    android.util.Log.d(TAG, getPrefix(obj) + str1 + str2);
20.REM }
21.REM If you want to enable the Log.d(), you need to type "adb shell setprop log.tag.Telecom V"
22.REM in your console, and kill the process of com.android.server.telecom, then Log.d() is enabled.
23.REM But if you reboot your device, the Log.d() is disabled, so we write the TAG to property system
24.REM to enable Log.d() forever. If you have any questions, please feel free to let me know.
25.REM Email: yihongyuelan@gmail.com
26. 
27.REM Steps:
28.REM 1. Get your device root permission.
29.REM 2. Running the OpenHideLogs.bat;
30. 
31. 
32.echo.
33.set NOROOTSTR=adbd cannot run as root
34.set ROOTSTR=adbd is already running as root
35.set BUILDTYPE=user
36. 
37.for /f "delims=" %%a in ('adb shell getprop ro.build.type'do set "build_type=%%a"
38.echo Your device is %build_type% Mode
39.echo.
40. 
41.:ISENABLED
42.for /f "delims=" %%c in ('adb shell getprop log.tag.InCall'do set "check=%%c"
43.if "%check%" == "V" (
44.echo Hidden Logs has been enabled!
45.pause
46.exit
47.else (
48.echo Hidden Logs hasn't been enabled!
49.)
50. 
51.echo.
52.for /f "delims=" %%b in ('adb root'do set "str=%%b"
53.REM echo %str%
54.set EXISTS_FLAG=false
55.echo %str%|find "%ROOTSTR%">nul&&set EXISTS_FLAG=true
56.if "%EXISTS_FLAG%"=="true" (
57.echo Checking ROOT permission PASS
58.ping -n 5 127.0.0.1 >nul
59.adb remount
60.if "%build_type%" == "%BUILDTYPE%" (
61.adb shell "echo log.tag.InCall=V                    >> /system/build.prop"
62.adb shell "echo log.tag.Telephony=V                 >> /system/build.prop"
63.adb shell "echo log.tag.Telecom=V                   >> /system/build.prop"
64.adb shell "echo log.tag.TelecomFramework=V          >> /system/build.prop"
65.adb shell "echo log.tag.Mms=V                       >> /system/build.prop"
66.adb shell "echo log.tag.MessageTemplateProvider=V   >> /system/build.prop"
67.adb shell "echo log.tag.CarrierText=V               >> /system/build.prop"
68.else (
69.adb push local.prop /data/
70.adb shell chmod 644 /data/local.prop
71.adb shell chown system:system /data/local.prop
72.)
73.adb reboot
74.adb wait-for-device
75.goto :ISENABLED
76.else (
77.echo Checking ROOT permission FAIL
78.echo Please get the root privileges for adbd and try again
79.pause
80.exit
81.)

其中local.prop内容如下:

view sourceprint?
1.log.tag.InCall=V
2.log.tag.Telephony=V
3.log.tag.Telecom=V
4.log.tag.TelecomFramework=V
5.log.tag.Mms=V
6.log.tag.MessageTemplateProvider=V
7.log.tag.CarrierText=V

脚本同步更新到github上,后续如有更新请查看github

小结

起初,看到android.util.Log.isLoggable(TAG, android.util.Log.DEBUG)代码,想当然的认为如果在userdebug的版本中isLoggable会返回true,结果查看后发现相关log并没有打印,进一步的分析后发现isLoggable背后的实现原理,同时也体会到了使用isLoggable控制log输出的灵活性。对于开发者来说,可以很好的利用isLoggable开启user版系统中的隐藏log,从而为相关问题提供更详细的log。对于isLoggable的重要知识点,总结如下:

1. isLoggable默认阈值是4 (INFO)

如果log level小于4 (INFO),即3 (DEBUG) 和2 (VERBOSE),则isLoggable返回false;

2. isLoggable可以通过设置属性值使其返回true

通过设置如log.tag.InCall D的属性,可以使得对应的isLoggable返回true,但需要注意的是,在设置属性之后需要重启相关进程,也可以通过adb shell stop & adb shell start重启Zygote及其子进程,不过该方法在完全重启设备后失效;

3. 设置属性文件可以永久使isLoggable返回true

在userdebug/eng版本中,可以将属性值log.tag.InCall=D写入/data/local.prop文件,这样isLoggable返回为true,并且在设备重启之后依然有效。如果在user版的系统中已经获取到root权限,可以向/system/build.prop中追加属性值,也可以达到重启后永久使isLoggable返回true的目的;

参考:

深入讲解Android Property机制 :本文详细分析了Android 4.4 Android Property的各个流程

Android的init过程(二):初始化语言(init.rc)解析:本文详细分析init.rc的解析过程,注意nargs在解析是会先执行nargs++

Android SystemProperties设置/取得系统属性的用法总结:本文是Android Property系统的集合贴

下载:http://www.it165.net/uploadfile/files/2015/0609/OpenHiddenLogs.zip

转载于:https://www.cnblogs.com/dirt2/p/6044133.html

相关文章:

SLAM精度测评——rpg_trajectory_evaluatio

1. install https://github.com/ccxslam/rpg_trajectory_evaluation#install 下载catkin_simple&#xff1a;https://github.com/catkin/catkin_simple 建立工作空间 src下载&#xff0c;编译&#xff0c;然后下载rpg_trajectory_evaluatio,编译安装即可。 &#xff12;&a…

STL set multiset

STL容器大的方向分为两类&#xff0c;序列式容器和关联式容器。 这两者通过数据在容器内的排列来区分。关联容器和顺序容器的根本不同在于&#xff1a;关联容器中的元素是按关键字来保存和访问的&#xff0c;而顺序容器中的元素则是按它们在容器中的位置来顺序保存和访问的。 …

Windows 消息循环(1) - 概览

本文从消息循环是如何驱动程序的这个角度&#xff0c;对 Windows 消息循环进行概览性介绍。 使用 EN5 课件获得更好的阅读体验&#xff1a; 【希沃白板5】课件分享 : 《Windows培训 - 消息循环》https://r302.cc/q2d1jB 点击链接直接预览课件 1 程序是怎么跑起来的&#xff1f;…

得到的旋转向量和平移向量转换成旋转矩阵 (SE(3))

理论过程 头文件说明 1.使用罗德里格斯公式需要包含头文件为#include<opencv2/calib3d.hpp> 2.使用函数cv2eigen需要包含头文件<opencv2/core/eigen.hpp>&#xff0c;但是在则之前要包含一个对eigen定义的头文件&#xff0c;否则会报eigen.hpp文件的错&#xff0c;…

[译稿]同步复制提议 2010-09

2019独角兽企业重金招聘Python工程师标准>>> 同步复制9/2010议案 目录 [隐藏] 1 PAGE状态 2 有何不同之处这个补丁&#xff1f; 3 同步复制概述 4 用户视角 4.1 管理员视角 5 实现 5.1 STANDBY 5.2 MASTER 6 CODE 7 性能分析 8 尚未实现 9 &#xff0c;其他问题 PAG…

STL vector

1、vector是表示可变大小数组的序列容器。 2、就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;它的大小是可以动态改变的&#xff0c;而且它的大小会…

JavaScript 复习之数据类型

一、简介 JavaScript 的数据类型有 7 种&#xff1a; 数值&#xff08;number&#xff09;字符串&#xff08;string&#xff09;布尔值&#xff08;boolean&#xff09;undefinednull对象&#xff08;object&#xff09;Symbol&#xff08;ES6 中新增的类型&#xff0c;表示独…

Nginx反代配置

一、ngx_http_proxy_module模块ngx_http_proxy_module模块可根据用户请求的uri传递至后端服务器&#xff0c;实现反向代理命令&#xff1a;1.proxy_pass设置一个代理服务器的地址&#xff0c;协议&#xff0c;和一个可选的URI的位置应该映射。作为一个协议&#xff0c;“HTTP”…

STL queue priority_queue

queue 队列 queue 队列 就像排队一样&#xff0c;后来的排在后面&#xff0c;先来的先出队。所以只能对队首和队尾的元素进行操作 back()返回最后一个元素empty()如果队列空则返回真front()返回第一个元素pop()删除第一个元素push()在末尾加入一个元素size()返回队列中元素的…

镜头评价指标及测试方法(二)—畸变与分辨率

一、畸变 畸变&#xff08;distortion&#xff09;也称为失真&#xff0c;是由于光阑球差的影响&#xff0c;不同视场的主光线通过光学系统后与高斯像面的交点高度不等于理想像高&#xff0c;两者之差就是畸变。因此畸变只改变轴外物点在理想面上的成像位置&#xff0c;使像的形…

优秀Java程序员应该知道的20个实用开源库

一个优秀且经验丰富的Java开发人员的特点之一是对API的广泛了解&#xff0c;包括JDK和第三方库。我花了很多时间学习API&#xff0c;特别是在阅读Effective Java 3rd Edition之后&#xff0c;Joshua Bloch建议如何使用现有的API进行开发&#xff0c;而不是为常用的东西写新的代…

sersync 同步

Sersync数据同步rsync是类unix系统下的数据镜像备份工具——remote sync。一款快速增量备份工具 Remote Sync&#xff0c;远程同步支持本地复制&#xff0c;或者与其他SSH、rsync主机同步。它的特性如下&#xff1a;v 可以镜像保存整个目录树和文件系统。v 可以很容易做到保持原…

python-opencv 形态学

五、形态学运算 检测边和 角点 形态学算子检测图像中的边缘和拐角&#xff08;实际用&#xff1a;Canny或Harris等算法&#xff09; 5.1 检测边缘 形态学检测边缘的原理&#xff1a;在膨胀时&#xff0c;图像中的物体会想周围“扩张”&#xff1b;腐蚀时&#xff0c;图像中的物…

【 HihoCoder】1082 The Marshtomp has seen it all before (暴力 或 脑力)

https://vjudge.net/problem/HihoCoder-1082 暴力 #include <iostream> #include <cstring>using namespace std;char s[205];int main() {int i;while(gets(s)){i 0;int len strlen(s);while(i<len){if((s[i]m||s[i]M)&&(s[i1]a||s[i1]A)&&am…

java 多维数组转化为字符串

int[][] a {{1,2,3},{4,5,7}};System.out.println(Arrays.deepToString(a)); Arrays.deepToString()此方法是为了将多维数组转换为字符串而设计的。 三维二维都可以解决;转载于:https://www.cnblogs.com/lishuaiqi/p/10428612.html

python-opencv 轮廓检测

轮廓检测 图像处理中经常用到轮廓检测,OpenCV-python接口中使用cv2.findContours()函数来查找检测物体的轮廓。 import cv2img cv2.imread(D:\\test\\contour.jpg) gray cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret, binary cv2.threshold(gray,127,255,cv2.THRESH_BINARY)…

JavaDate类

在JDK1.0中&#xff0c;Date类是唯一的一个代表时间的类&#xff0c;但是由于Date类不便于实现国际化&#xff0c;所以从JDK1.1版本开始&#xff0c;推荐使用Calendar类进行时间和日期处理。这里简单介绍一下Date类的使用。1、使用Date类代表当前系统时间Date d new Date();Sy…

Jupyter Notebook使用教程

1、启动 在终端中输入以下命令&#xff1a; jupyter notebook --allow-root执行命令之后&#xff0c;在终端中将会显示一系列notebook的服务器信息&#xff0c;同时浏览器将会自动启动Jupyter Notebook。 启动过程中终端显示内容如下&#xff1a; $ jupyter notebook [I 08…

一次性理清JavaScript变量等高难度面试问题

主要是解决JavaScript中比较难懂的部分&#xff0c;当然了&#xff0c;这部分经常在面试题中露面&#xff0c;这篇文章主要是讲解解题思路&#xff0c;对新手会有很大帮助&#xff08;如果你仔细看的话&#xff09;。书籍方面&#xff0c;我看的是《你不知道的javascript》,精髓…

yolov3(一:模型训练)

第一部分&#xff1a;训练已有的voc datasets 搞清楚该算法的模型训练流程 Darknet是Joseph维护的开源的神经网络框架&#xff0c;使用C语言编写&#xff1a;https://pjreddie.com/darknet/yolo/ Darknet快速&#xff0c;易于安装&#xff0c;同时支持CPU和GPU计算&#xff1…

Ios生产证书申请(含推送证书)

一、Mac机上生成请求文件。 Mac机上点击证书助手 > 从证书颁发机构请求证书 > 得到CertificateSigningRequest.certSigningRequest请求文件&#xff08;此请求证书建议一直保存&#xff0c;因为根证书的生成需要使用此请求文件&#xff0c;根证书多个app可以使用一个&…

【Python】SyntaxError: unexpected EOF while parsing

找到错误的地方是 少打了半个括号 emmm 1、可能是语法问题&#xff0c;需要自己检查代码 2、可能是用python2.7来运行python3.0的代码不兼容

华为云家庭视频监控帮你一起守护家

设想一下&#xff1f;离开家了突然想起家里空调没关怎么办&#xff1f;家里没人有陌生人入侵了怎么办&#xff1f;不在家家里老人出事了怎么办&#xff1f; 不用愁&#xff0c;总有办法解决的&#xff0c;这些日常生活中极容易遇到的事情&#xff0c;没有分身术的时候&#xff…

SLAM之特征匹配(三)————RANSAC------LO-RANSAC Algorithm

matlab 编译loransac&#xff0c;lapack mex ranH.c时一直链接错误。 原来mex在编译多个文件时要把所有的C文件都列出来。命令如下&#xff1a; mex loransacH.mex.c ranH.c utools.c Htools.c lapwrap.c matutl.c rtools.c -ID:\lapack\headers\lapack -LD:\lapack - lcbia.l…

【Codeforces】1136C Nastya Is Transposing Matrices (矩阵转置)

http://codeforces.com/contest/1136/problem/C 第一个矩阵可否通过转置&#xff0c;变换成第二个矩阵&#xff0c;可以的话输出“YES”&#xff0c;不可以的话&#xff0c;输出“NO” 转置之后&#xff0c;对角线元素是不变的 用map&#xff0c;或者vector 都可以 #includ…

linux基础篇-02,linux时间管理date hwclock cal 简述

################################################时间管理1&#xff0c;date:系统时钟查看当前系统时间[rootJameszhan etc]# date2016年 11月 14日 星期一 20:16:37 CST################################################设定系统时间 2016年 07月 20日 星期三 10:30:00 CST…

Spark shuffle调优

Spark shuffle是什么Shuffle在Spark中即是把父RDD中的KV对按照Key重新分区&#xff0c;从而得到一个新的RDD。也就是说原本同属于父RDD同一个分区的数据需要进入到子RDD的不同的分区。现在的spark版本默认使用的是sortshuffle;shuffle在哪里产生shuffle在spark的算子中产生,也就…

多传感器融合之滤波(一)——卡尔曼滤波(KF)推导

c参考资料&#xff1a;https://www.bzarg.com/p/how-a-kalman-filter-works-in-pictures/ 卡尔曼滤波本质上是一个数据融合算法&#xff0c;将具有同样测量目的、来自不同传感器、(可能) 具有不同单位 (unit) 的数据融合在一起&#xff0c;得到一个更精确的目的测量值。 卡尔…

【HDU】1284 钱币兑换问题 (想一想)

http://acm.hdu.edu.cn/showproblem.php?pid1284 除以三&#xff0c;看最多能放多少个三分的硬币&#xff0c;加一表示全部都是一分的硬币着一种情况。之后用一个循环看一下&#xff0c;有多少种情况 因为确定了有几个三分&#xff0c;有几个两分&#xff0c;一分的也就自然…

抓取网页的脚本 【修复】

之前张耀老师的网页脚本由于51cto升级&#xff0c;课程列表页面改用javascript失效了笔者发现视频课程页面右边的列表都为静态化后的视频课程地址&#xff0c;遂将老师初始版本的脚本进行了修改&#xff0c;在对视频课程页面使用时结果正常&#xff0c;遂将及修改后的脚本和部分…