
在程序设计过程中,我们总是希望自己设计的程序是天衣无缝的,但这几乎又是不可能的。即使程序编译通过,同时也实现了所需要的功能,也并不代表程序就已经完美无缺了,因为运行程序时还可能会遇到异常,例如当我们设计一个为用户计算除法的程序时,用户很有可能会将除数输入为零,又例如当我们需要打开一个文件的时候确发现该文件已经被删除了……类似的这种情况很有很多,针对这些特殊的情况,不加以防范是不行的。 我们通常希望自己编写的程序能够在异常的情况下也能作出相应的处理,而不至于程序莫名其妙地中断或者中止运行了。在设计程序时应充分考虑各种异常情况,并加以处理。 在C++中,一个函数能够检测出异常并且将异常返回,这种机制称为抛出异常。当抛出异常后,函数调用者捕获到该异常,并对该异常进行处理,我们称之为异常捕获。 C++新增throw关键字用于抛出异常,新增catch关键字用于捕获异常,新增try关键字尝试捕获异常。通常将尝试捕获的语句放在 try{ } 程序块中,而将异常处理语句置于 catch{ } 语句块中。 异常处理的基本语法如下所述。首先说一下抛出异常的基本语法: throw 表达式; 抛出异常由throw关键字加上一个表达式构成。抛出异常后需要捕获异常以及异常处理程序,其基本语法如下: try { //可能抛出异常的语句 } catch (异常类型1) { //异常类型1的处理程序 } catch (异常类型2) { //异常类型2的处理程序 } // …… catch (异常类型n) { //异常类型n的处理程序 } 由try程序块捕获throw抛出的异常,然后依据异常类型运行catch程序块中的异常处理程。catch程序块顺序可以是任意的,不过均需要放在try程序块之后。 [例1] C++异常处理示例: #include<iostream> using namespace std; enum index{underflow, overflow}; int array_index(int *A, int n, int index); int main() { int *A = new int[10]; for(int i=0; i<10; i++) A[i] = i; try { cout<<array_index(A,10,5)<<endl; cout<<array_index(A,10,-1)<<endl; cout<<array_index(A,10,15)<<endl; } catch(index e) { if(e == underflow) { cout<<"index underflow!"<<endl; exit(-1); } if(e == overflow) { cout<<"index overflow!"<<endl; exit(-1); } } return 0; } int array_index(int *A, int n, int index) { if(index < 0) throw underflow; if(index > n-1) throw overflow; return A[index]; } 本例展示了一个数组越界的异常捕获程序。array_index函数用于返回数组index下标的数值,如果出现异常则抛出异常。try程序块中的程序语句为可能出现异常情况的语句,catch则为针对异常的处理语句。在程序一开始我们定义了一个全局的枚举类型变量index,并且定义了两个值,分别为underflow和overflow,这两个值作为抛出异常的返回值。当在主函数要求输出越界的数组值时,调用array_index函数,一旦有预定异常抛出,则通过try捕获并根据catch语句针对异常情况作出处理。 在前面我们介绍了new和delete动态分配内存操作符,如果new或new[]不能成功分配所请求的,将会抛出一个bad_alloc异常。在使用new或new[]操作符分配动态内存,可以通过如下方式检测并捕获存储空间分配失败的异常。 [例2] 捕获new、new[] 抛出的异常: int * p; try { p = new int[10]; } catch(bad_alloc) { cerr<<"allocate failure!"<<endl; exit(-1); } 在C语言中,异常通常是通过函数返回值获得,但这样一来,函数是否产生异常则需要通过检测函数的返回值才能得知。而在C++中,当函数抛出一个返回值时,即使不用try和catch语句,异常还是会被处理的,系统会自动调用默认处理函数unexpected来执行。
在C语言中,动态分配和释放内存的函数是malloc、calloc和free,而在C++语言中,new、new[]、delete和delete[]操作符通常会被用来动态地分配内存和释放内存。 需要注意的是new、new[]、delete和delete[]是操作符,而非函数;new和delete也是C++的关键字。 操作符new用于动态分配单个空间,而new[]则是用于动态分配一个数组,操作符delete用于释放由new分配的空间,delete[]则用于释放new[]分配的一个数组。 “new 数据类型”即为new关键字的基本语法,可以动态的分配一个数据类型大小的空间。例如: int *p = new int; 为p指针分配了一个int型的空间。new操作符根据请求分配的数据类型来推断所需的空间大小。 new[] 则是为了分配一个数组的空间。具体语法如: int *A = new int[10]; 该语句为A指针分配了一个数组的空间,该数组有10个int数组成员,如果分配成功,则p指针指向首地址,并且数组10个成员的地址是连续的,其地址分别为A、A+1、A+2、……、A+9。 delete操作符则专门用于释放由new分配的动态存储空间,在前面我们为p分配了一个int型的空间,我们可以按照如下的方式释放它: delete p; delete[] 则用于释放掉由new[]分配的数组空间,在前面我们为A指针分配了十个int单元,构成了一个数组,可以按照如下方式释放掉该空间: delete[] p; 为了避免内存泄露,通常new和delete、new[]和delete[]操作符应该成对出现,并且不要将这些操作符与C语言中动态分配内存和释放内存的几个函数一起混用。建议在编写C++程序时尽量使用new、new[]、delete和delete[]操作符进行动态内存分配和释放,而不要使用C语言中内存分配和释放的函数,这是因为new、new[]、delete和delete[]操作符可以使用C++的一些特性,如类的构造函数和析构函数,能够更好地管理C++程序的内存。
C++语言新增关键字 inline,用于将一个函数声明为内联函数。在程序编译时,编译器会将内联函数调用处用函数体替换,这一点类似于C语言中的宏扩展。 采用内联函数可以有效避免函数调用的开销,程序执行效率更高。使用内联函数的缺点就是,如果被声明为内联函数的函数体非常大,则编译器编译后程序的可执行码将会变得很大。另外,如果函数体内出现循环或者其它复杂的控制结构的时候,这个时候处理这些复杂控制结构所花费的时间远大于函数调用所花的时间,因此如果将这类函数声明为内联函数,意义不大,反而会使得编译后可执行代码边长。 通常在程序设计过程中,我们会将一些频繁被调用的短小函数声明为内联函数。 为了使得inline声明内联函数有效,我们必须将inline关键字与函数体放在一起才行,否则inline关键字是不能成功将函数声明内联函数的。如例1所示,inline关键字则无丝毫作用,而例2中则成功将swap函数声明为了一个内联函数。 [例1] inline 关键字放在函数声明处不会起作用: inline void swap(int &a, int &b); void swap(int &a, int &b) { int temp = a; a = b; b = temp; } [例2] inline 关键字应该与函数体放在一起: void swap(int &a, int &b); inline void swap(int &a, int &b) { int temp = a; a = b; b = temp; }
[toc] 在C++语言中新增了四个关键字static_cast、const_cast、reinterpret_cast和dynamic_cast。这四个关键字都是用于强制类型转换的。我们逐一来介绍这四个关键字。 1) static_cast 在C++语言中static_cast用于数据类型的强制转换,强制将一种数据类型转换为另一种数据类型。例如将整型数据转换为浮点型数据。 [例1]C语言所采用的类型转换方式: int a = 10; int b = 3; double result = (double)a / (double)b; 例1中将整型变量a和b转换为双精度浮点型,然后相除。在C++语言中,我们可以采用static_cast关键字来进行强制类型转换,如下所示。 [例2]static_cast关键字的使用: int a = 10; int b = 3; double result = static_cast<double>(a) / static_cast<double>(b); 在本例中同样是将整型变量a转换为双精度浮点型。采用static_cast进行强制数据类型转换时,将想要转换成的数据类型放到尖括号中,将待转换的变量或表达式放在元括号中,其格式可以概括为如下形式: static_cast <类型说明符> (变量或表达式) 2) const_cast 在C语言中,const限定符通常被用来限定变量,用于表示该变量的值不能被修改。而const_cast则正是用于强制去掉这种不能被修改的常数特性,但需要特别注意的是const_cast不是用于去除变量的常量性,而是去除指向常数对象的指针或引用的常量性,其去除常量性的对象必须为指针或引用。 [例3]一个错误的例子: const int a = 10; const int * p = &a; *p = 20; //compile error int b = const_cast<int>(a); //compile error 在本例中出现了两个编译错误,第一个编译错误是*p因为具有常量性,其值是不能被修改的;另一处错误是const_cast强制转换对象必须为指针或引用,而例3中为一个变量,这是不允许的! [例4]const_cast关键字的使用 #include<iostream> using namespace std; int main() { const int a = 10; const int * p = &a; int *q; q = const_cast<int *>(p); *q = 20; //fine cout <<a<<" "<<*p<<" "<<*q<<endl; cout <<&a<<" "<<p<<" "<<q<<endl; return 0; } 在本例中,我们将变量a声明为常量变量,同时声明了一个const指针指向该变量(此时如果声明一个普通指针指向该常量变量的话是不允许的,Visual Studio 2010编译器会报错),之后我们定义了一个普通的指针*q。将p指针通过const_cast去掉其常量性,并赋给q指针。之后我再修改q指针所指地址的值时,这是不会有问题的。 最后将结果打印出来,运行结果如下: 10 20 20 002CFAF4 002CFAF4 002CFAF4 查看运行结果,问题来了,指针p和指针q都是指向a变量的,指向地址相同,而且经过调试发现002CFAF4地址内的值确实由10被修改成了20,这是怎么一回事呢?为什么a的值打印出来还是10呢? 其实这是一件好事,我们要庆幸a变量最终的值没有变成20!变量a一开始就被声明为一个常量变量,不管后面的程序怎么处理,它就是一个常量,就是不会变化的。试想一下如果这个变量a最终变成了20会有什么后果呢?对于这些简短的程序而言,如果最后a变成了20,我们会一眼看出是q指针修改了,但是一旦一个项目工程非常庞大的时候,在程序某个地方出现了一个q这样的指针,它可以修改常量a,这是一件很可怕的事情的,可以说是一个程序的漏洞,毕竟将变量a声明为常量就是不希望修改它,如果后面能修改,这就太恐怖了。 在例4中我们称“*q=20”语句为未定义行为语句,所谓的未定义行为是指在标准的C++规范中并没有明确规定这种语句的具体行为,该语句的具体行为由编译器来自行决定如何处理。对于这种未定义行为的语句我们应该尽量予以避免! 从例4中我们可以看出我们是不想修改变量a的值的,既然如此,定义一个const_cast关键字强制去掉指针的常量性到底有什么用呢?我们接着来看下面的例子。 例5: #include<iostream> using namespace std; const int * Search(const int * a, int n, int val); int main() { int a[10] = {0,1,2,3,4,5,6,7,8,9}; int val = 5; int *p; p = const_cast<int *>(Search(a, 10, val)); if(p == NULL) cout<<"Not found the val in array a"<<endl; else cout<<"have found the val in array a and the val = "<<*p<<endl; return 0; } const int * Search(const int * a, int n, int val) { int i; for(i=0; i<n; i++) { if(a[i] == val) return &a[i]; } return NULL; } 在例5中我们定义了一个函数,用于在a数组中寻找val值,如果找到了就返回该值的地址,如果没有找到则返回NULL。函数Search返回值是const指针,当我们在a数组中找到了val值的时候,我们会返回val的地址,最关键的是a数组在main函数中并不是const,因此即使我们去掉返回值的常量性有可能会造成a数组被修改,但是这也依然是安全的。 对于引用,我们同样能使用const_cast来强制去掉常量性,如例6所示。 例6: #include<iostream> using namespace std; const int & Search(const int * a, int n, int val); int main() { int a[10] = {0,1,2,3,4,5,6,7,8,9}; int val = 5; int &p = const_cast<int &>(Search(a, 10, val)); if(p == NULL) cout<<"Not found the val in array a"<<endl; else cout<<"hvae found the val in array a and the val = "<<p<<endl; return 0; } const int & Search(const int * a, int n, int val) { int i; for(i=0; i<n; i++) { if(a[i] == val) return a[i]; } return NULL; } 了解了const_cast的使用场景后,可以知道使用const_cast通常是一种无奈之举,同时也建议大家在今后的C++程序设计过程中一定不要利用const_cast去掉指针或引用的常量性并且去修改原始变量的数值,这是一种非常不好的行为。 3) reinterpret_cast 在C++语言中,reinterpret_cast主要有三种强制转换用途: 改变指针或引用的类型 将指针或引用转换为一个足够长度的整形 将整型转换为指针或引用类型。 在使用reinterpret_cast强制转换过程仅仅只是比特位的拷贝,因此在使用过程中需要特别谨慎! 例7 int *a = new int; double *d = reinterpret_cast<double *>(a); 在例7中,将整型指针通过reinterpret_cast强制转换成了双精度浮点型指针。reinterpret_cast可以将指针或引用转换为一个足够长度的整形,此中的足够长度具体长度需要多少则取决于操作系统,如果是32位的操作系统,就需要4个字节及以上的整型,如果是64位的操作系统则需要8个字节及以上的整型。 4) dynamic_cast dynamic_cast用于类的继承层次之间的强制类型转换,我们将在讲到类的继承的时候再来介绍dynamic_cast。
[TOC] 引用(Reference)是C++语言相对于C语言的又一个扩充,类似于指针,只是在声明的时候用&取代了*。引用可以看做是被引用对象的一个别名,在声明引用时,必须同时对其进行初始化。引用的声明方法如下: 类型标识符 &引用名 = 被引用对象 [例1]C++引用示例: int a = 10; int &b = a; cout<<a<<" "<<b<<endl; cout<<&a<<" "<<&b<<endl; 在本例中,变量b就是变量a的引用,程序运行结果如下: 10 10 0018FDB4 0018FDB4 从这段程序中我们可以看出变量a和变量b都是指向同一地址的,也即变量b是变量a的另一个名字,也可以理解为0018FDB4空间拥有两个名字:a和b。由于引用和原始变量都是指向同一地址的,因此通过引用也可以修改原始变量中所存储的变量值,如例2所示,最终程序运行结果是输出两个20,可见原始变量a的值已经被引用变量b修改。 [例2]通过引用修改原始变量中的值: int a = 10; int &b = a; b = 20; cout<<a<<" "<<b<<endl; 如果我们不希望通过引用来改变原始变量的值时,我们可以按照如下的方式声明引用: const 类型标识符 & 引用名 = 被引用的变量名 这种引用方式成为常引用。如例3所示,我们声明b为a的常引用,之后尝试通过b来修改a变量的值,结果编译报错。虽然常引用无法修改原始变量的值,但是我们仍然可以通过原始变量自身来修改原始变量的值,如例3中,我们用a=20;语句将a变量的值由10修改为20,这是没有语法问题的。 [例3]不能通过常引用来修改原始值: int a = 10; const int &b = a; b = 20; //compile error a = 20; 通过例2,我们可以知道通过引用我们可以修改原始变量的值,引用的这一特性使得它用于函数传递参数或函数返回值时非常有用。 1) 函数引用参数 如果我们在声明或定义函数的时候将函数的形参指定为引用,则在调用该函数时会将实参直接传递给形参,而不是将实参的拷贝传递给形参。如此一来,如果在函数体中修改了该参数,则实参的值也会被修改。这跟函数的普通传值调用还是有区别的。 [例3]函数的引用传值: #include<iostream> using namespace std; void swap(int &a, int &b); int main() { int num1 = 10; int num2 = 20; cout<<num1<<" "<<num2<<endl; swap(num1, num2); cout<<num1<<" "<<num2<<endl; return 0; } void swap(int &a, int &b) { int temp = a; a = b; b = temp; } 运行结果: 10 20 20 10 在本例中我们将swap函数的形参声明为引用,在调用swap函数的时候程序是将变量num1和num2直接传递给形参的,其中a是num1的别名,b是num2的别名,在swap函数体中交换变量a和变量b的值,也就相当于直接交换变量num1和变量num2的值了,因此程序最后num1=20,num2=10。 2) 函数引用返回值 在C++中非void型函数需要返回一个返回值,类似函数形参,我们同样可以将函数的返回值声明为引用。普通的函数返回值是通过传值返回,即将关键字return后面紧接的表达式运算结果或变量拷贝到一个临时存储空间中,然后函数调用者从临时存储空间中取到函数返回值,如例4所示。 [例4]函数的普通返回值: #include<iostream> using namespace std; int valplus(int &a); int main() { int num1 = 10; int num2; num2 = valplus(num1); cout<<num1<<" "<<num2<<endl; return 0; } int valplus(int &a) { a = a + 5; return a; } 在例4中,valplus函数采用的是普通的传值返回,也即将变量a的结果加上5之后,将结果拷贝到一个临时存储空间,然后再从临时存储空间拷贝给num2变量。 当我们将函数返回值声明为引用的形式时,如例5所示。虽然例5运行结果和例4是相同的,但例5中的valplus函数在将a变量加上5之后,其运算结果是直接拷贝给num2的,中间没有经过拷贝给临时空间,再从临时存储空间中拷贝出来的这么一个过程。这就是普通的传值返回和引用返回的区别。 [例5]函数的引用返回值: #include<iostream> using namespace std; int & valplus(int &a); int main() { int num1 = 10; int num2; num2 = valplus(num1); cout<<num1<<" "<<num2<<endl; return 0; } int & valplus(int &a) { a = a + 5; return a; } 此外,我们还需要注意一个小问题。如果我们将例5中的valplus函数定义成例6中所示的形式,那么这段程序就会产生一个问题,变量b的作用域仅在这个valplus函数体内部,当函数调用完成,b变量就会被销毁。而此时我们若将b变量的值通过引用返回拷贝给变量num2的时候,有可能会出现在拷贝之前b变量已经被销毁,从而导致num2变量获取不到返回值。虽然这种情况在一些编译器中并没有发生,但是我们在设计程序的时候也是应该尽量避免这一点的。 在例4和例5中,我们就是为了避免这一点才采用的引用传递参数。普通的传值返回则不存在这样的问题,因为编译器会将返回值拷贝到临时存储空间后再去销毁b变量的。 [例6]一个可能获取不到返回值的例子: int & valplus(int a) { int b = a+5; return b; }
Android 官方网站是:https://www.android.com/ 其下的开发者网站是:https://developer.android.com/ 其下的源代码文档网站是:https://source.android.com/ 我相信作为正当上网的网民应该是打不开上面的网址的,后来在中国开通了google.cn,可以用了谷歌翻译(https://translate.google.cn/)。感谢Google.cn,可以打开了Android开发者网站的源代码文档: Android 开发者网站:https://developer.android.google.cn/ Android 源代码文档:https://source.android.google.cn/ 有了Google.cn的Android源代码文档我就不再搬砖了~,用Google浏览器还可以自带网页翻译,下面是Android 源代码文档的其中一篇。 Android 电源配置文件 电池使用统计信息 电源配置文件中的值 Android 电源配置文件 电池使用信息来自电池使用统计信息和电源配置文件中的值。 电池使用统计信息 框架可通过跟踪设备组件在不同状态下维持的时间来自动确定电池使用统计信息。当组件(WLAN 芯片组、手机无线装置、蓝牙、GPS、显示屏和 CPU)状态发生改变(开/关、空闲/全功耗、低/高亮度等)时,控制服务会向框架中的 BatteryStats 服务报告状态改变信息。BatteryStats 会不断地收集信息,并存储这些信息以便在重新启动后继续使用。该服务不会直接跟踪电池中消耗的电流,而是通过收集计时信息来估算不同组件所消耗的电量。 该框架使用以下方法收集统计信息: 推送。服务察觉到组件状态发生变化后,会将状态变化推送到 BatteryStats 服务中。 拉取。对于应用使用的 CPU 等组件,框架会在转换点(例如启动活动或停止活动)自动拉取数据以截取快照。 资源消耗与使用资源的应用相关。当多个应用同时使用某项资源(例如防止系统挂起的唤醒锁)时,框架会将资源消耗量分摊到这些应用上,但不一定会均分。 为了避免由于系统关闭事件而丢失电池使用统计信息(这些统计信息可能表明存在电池功耗问题,比如由于电池电量耗尽而关闭),框架会大约每 30 分钟发送一次统计信息。 电池使用统计信息完全由框架处理,不需要原始设备制造商 (OEM) 修改。 电源配置文件中的值 注意:设备制造商必须提供组件的电源配置文件,该配置文件定义了组件的电流消耗值以及该组件在一段时间内大概消耗的电量。有关此配置文件的定义,请查看 platform/frameworks/base/core/res/res/xml/power_profile.xml。要获得与这些设置相关的指导,请参阅电源值。 在电源配置文件中,功耗表示额定电压下的电流消耗量,单位为毫安 (mA),也可用微安 (uA) 表示(分数值)。该值应代表电池上消耗的电流,而非与电池消耗的电流不对应的相应电源轨的值。 例如,显示屏电源配置文件列出了当显示屏开启状态下保持最低亮度和最高亮度时需消耗的电流量 (mA)。为了确定显示屏常亮时所需的电源成本(即由显示屏组件所消耗的电池量),框架会跟踪在各个亮度级别下维持的时间,然后将这些时间间隔乘以通过插值算法计算的显示亮度成本。 该框架还会将每个应用的 CPU 时间乘以在特定速度运行 CPU 所需的毫安量。通过该计算方法可以创建一个应用电池消耗量(通过执行 CPU 代码)的相对排名(应用在前台的时间和包括后台活动在内的总时间将分开报告)。 Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the Apache 2.0 License. For details, see our Site Policies. Java is a registered trademark of Oracle and/or its affiliates. 上次更新日期:一月 2, 2018
在C语言中,通常会在采用格式化输入输出函数printf和scanf用于输入或输出数据或信息。在C++语言中,C语言的这一套输入输出库我们仍能使用,但是C++语言又自定义了一套新的、更容易使用的输入输出库。 在C++程序中,输入与输出可以看做是一连串的数据流,输入即可视为从文件或键盘中输入程序中的一串数据流,而输出则可以视为从程序中输出一连串的数据流到显示屏或文件中。 在编写C++程序时,如果需要使用输入输出时,则需要包含头文件iostream。在iostream中定义了用于输入输出的对象,例如常见的cin表示标准输入、cout表示标准输出、cerr表示标准错误 。 需要特别强调的是cin、cout、cerr不是C++中的关键字,其本质是函数调用,它们的实现采用的是C++的运算符重载,这些知识点将会在后续逐一介绍。其中cout和cerr的输出目的地都是显示器,但不同的是cout是带有缓冲的,而cerr则不带缓冲。 在我们使用cout进行输出时需要紧接着使用“<<”操作符,使用cin进行输入时需要紧接着使用“>>”操作符,这两个操作符可以自行分析所处理的数据类型,因此无需我们像使用scanf和printf那样设置输入输出格式化语句。 [例1]C++简单的输入输出代码示例: #include<iostream> using namespace std; int main() { int x; float y; cout<<"Please input an int number:"<<endl; cin>>x; cout<<"The int number is x= "<<x<<endl; cout<<"Please input a float number:"<<endl; cin>>y; cout<<"The float number is y= "<<y<<endl; return 0; } 这段程序的功能是提示用户输入一个整型和一个浮点型数字,然后将其显示在显示器上,这段代码的运行结果如下所示(↙表示用户按下enter键): Please input an int number: 8↙ The int number is x= 8 Please input a float number: 7.4↙ The float number is y= 7.4 语句cout<<"Please input a int number:"<>x;表示从标准输入中读入一个int型的数据并存入到x变量中。如果此时用户输入的不是int型数据,则会被强制转化为int型数据。语句cout<<"The int number is x= "< [例2]cin 连续输入示例: #include<iostream> using namespace std; int main() { int x; float y; cout<<"Please input an int number and a float number:"<<endl; cin>>x>>y; cout<<"The int number is x= "<<x<<endl; cout<<"The float number is y= "<<y<<endl; return 0; } 运行结果: Please input an int number and a float number: 8 7.4↙ The int number is x= 8 The float number is y= 7.4 在例2中我们用cin>>x>>y;连续从标准输入中读取一个整型和一个浮点型数字,然后分别存入到x和y中。输入操作符>>在读入下一个输入项前会忽略前一项后面的空格,如例2中,数字8和7.4之间有一个空格,当cin读入8后忽略空格,接着读取7.4。 当使用cin>>val输入变量时,如果输入一个变量到val中,则该表达式返回true,否则返回false。利用这一特性,我们可以连续输入数据,如例3所示。 [例3]使用 cin 连续输入数据: #include<iostream> using namespace std; int main() { int sum = 0; int val = 0; cout<<"Please input a number :"<<endl; while(cin>>val) { sum += val; cout<<"Please input next number :"<<endl; } cout<<"The sum of all number is sum = "<<sum<<endl; return 0; } 这个程序从标准输入中不断地读取数据并存入到val变量中,每读入一个数据就求一次和,直至用户输入文件结束符标识时,程序才会输出之前用户输入所有数据之和。
整型信号量 记录型信号量 利用信号量实现同步 利用信号量实现进程互斥 利用信号量实现前驱关系 分析进程同步和互斥问题的方法步骤 信号量机构是一种功能较强的机制,可用来解决互斥与同步的问题,它只能被两个标准的原语wait(S)和signal(S)来访问,也可以记为“P操作”和“V操作”。 原语是指完成某种功能且不被分割不被中断执行的操作序列,通常可由硬件来实现完成不被分割执行特性的功能。如前述的“Test-and-Set”和“Swap”指令,就是由硬件实现的原子操作。原语功能的不被中断执行特性在单处理机时可由软件通过屏蔽中断方法实现。 原语之所以不能被中断执行,是因为原语对变量的操作过程如果被打断,可能会去运行另一个对同一变量的操作过程,从而出现临界段问题。如果能够找到一种解决临界段问题的元方法,就可以实现对共享变量操作的原子性。 整型信号量 整型信号量被定义为一个用于表示资源数目的整型量S,wait和signal操作可描述为: wait(S){ while (S<=0); S=S-1; } signal(S){ S=S+1; } wait操作中,只要信号量S<=0,就会不断地测试。因此,该机制并未遵循“让权等待” 的准则,而是使进程处于“忙等”的状态。 记录型信号量 记录型信号量是不存在“忙等”现象的进程同步机制。除了需要一个用于代表资源数目的整型变量value外,再增加一个进程链表L,用于链接所有等待该资源的进程,记录型信号量是由于釆用了记录型的数据结构得名。记录型信号量可描述为: typedef struct{ int value; struct process *L; } semaphore; 相应的wait(S)和signal(S)的操作如下: void wait (semaphore S) { //相当于申请资源 S.value--; if(S.value<0) { add this process to S.L; block(S.L); } } wait操作,S.value–,表示进程请求一个该类资源,当S.value<0时,表示该类资源已分配完毕,因此进程应调用block原语,进行自我阻塞,放弃处理机,并插入到该类资源的等待队列S.L中,可见该机制遵循了“让权等待”的准则。 void signal (semaphore S) { //相当于释放资源 S.value++; if(S.value<=0){ remove a process P from S.L; wakeup(P); } } signal操作,表示进程释放一个资源,使系统中可供分配的该类资源数增1,故S.value++。若加1后仍是S.value<=0,则表示在S.L中仍有等待该资源的进程被阻塞,故还应调用wakeup 原语,将S.L中的第一个等待进程唤醒。 利用信号量实现同步 信号量机构能用于解决进程间各种同步问题。设S为实现进程P1、P2同步的公共信号量,初值为0。进程P2中的语句y要使用进程P1中语句x的运行结果,所以只有当语句x执行完成之后语句y才可以执行。其实现进程同步的算法如下: semaphore S = 0; //初始化信号量 P1 ( ) { // … x; //语句x V(S); //告诉进程P2,语句乂已经完成 } P2()){ // … P(S) ; //检查语句x是否运行完成 y; // 检查无误,运行y语句 // … } 利用信号量实现进程互斥 信号量机构也能很方便地解决进程互斥问题。设S为实现进程Pl、P2互斥的信号量,由于每次只允许一个进程进入临界区,所以S的初值应为1(即可用资源数为1)。只需把临界区置于P(S)和V(S)之间,即可实现两进程对临界资源的互斥访问。其算法如下: semaphore S = 1; //初化信号量 P1 ( ) { // … P(S); // 准备开始访问临界资源,加锁 // 进程P1的临界区 V(S); // 访问结束,解锁 // … } P2() { // … P(S); //准备开始访问临界资源,加锁 // 进程P2的临界区; V(S); // 访问结束,解锁 // … } 互斥的实现是不同进程对同一信号量进行P、V操作,一个进程在成功地对信号量执行了 P操作后进入临界区,并在退出临界区后,由该进程本身对该信号量执行V操作,表示当前没有进程进入临界区,可以让其他进程进入。 利用信号量实现前驱关系 信号量也可以用来描述程序之间或者语句之间的前驱关系。图2-8给出了一个前驱图,其中S1, S2, S3, …, S6是最简单的程序段(只有一条语句)。为使各程序段能正确执行,应设置若干个初始值为“0”的信号量。例如,为保证S1 -> S2、 S1 -> S3的前驱关系,应分别设置信号量a1、a2。同样,为了保证 S2 -> S4、S2 ->S5、S3 -> S6、S4 -> S6、S5 -> S6,应设置信号量bl、b2、c、d、e。 图2-8 前驱图举例 实现算法如下: semaphore al=a2=bl=b2=c=d=e=0; //初始化信号量 S1() { // … V(al); V(a2) ; //S1已经运行完成 } S2() { P(a1); //检查S1是否运行完成 // … V(bl); V(b2); // S2已经运行完成 } S3() { P(a2); //检查S1是否已经运行完成 // … V(c); //S3已经运行完成 } S4() { P(b1); //检查S2是否已经运行完成 // … V(d); //S4已经运行完成 } S5() { P(b2); //检查S2是否已经运行完成 // … V(e); // S5已经运行完成 } S6() { P(c); //检查S3是否已经运行完成 P(d); //检查S4是否已经运行完成 P(e); //检查S5是否已经运行完成 // …; } 分析进程同步和互斥问题的方法步骤 1) 关系分析。找出问题中的进程数,并且分析它们之间的同步和互斥关系。同步、互斥、前驱关系直接按照上面例子中的经典范式改写。 2) 整理思路。找出解决问题的关键点,并且根据做过的题目找出解决的思路。根据进程的操作流程确定P操作、V操作的大致顺序。 3) 设置信号量。根据上面两步,设置需要的信号量,确定初值,完善整理。
C++语言引入命名空间(Namespace)这一概念主要是为了避免命名冲突,其关键字为 namespace。 科技发展到如今,一个系统通常都不会仅由一个人来开发完成,不同的人开发同一个系统,不可避免地会出现变量或函数的命名冲突,当所有人的代码测试通过,没有问题时,将所有人的代码结合到一起,因为变量或函数重名而导致的问题将会造成一定的混乱,例如: int flag = 1; //小李声明的变量 // …… //中间间隔若干行代码 bool flag = true; //小韩声明的变量 注意:此例仅为解释命名空间所用,在公司的系统开发中并非如此中所述,完全仅靠命名空间来解决命名冲突的,具体编程规范可以参考林锐的《高质量程序设计指南》一书。 如上所示,因为个人习惯不同,小李喜欢声明int型变量用于逻辑判断,而小韩则更喜欢采用bool类型变量。但两个声明放到同一个函数中的时候,很明显编译器会提示出flag变量重新定义的错误。这种问题若不加以处理是无法编译通过的。 可以使用命名空间解决类似上面的命名冲突问题,例如: namespace Li{ //小李的变量声明 int flag = 1; } namespace Han{ //小韩的变量声明 bool flag = true; } 小李与小韩各自定义了以自己姓氏为名的命名空间,此时将小李与小韩的flag变量定义再置于同一个函数体中,则不会有任何问题,当然在使用这两个变量的时候需要指明所采用的是哪一个命名空间中的flag变量。 指定所使用的变量时需要用到“::”操作符,“::”操作符是域解析操作符。例如: Li::flag = 0; //使用小李定义的变量flag Han::flag = false; //使用小韩定义的变量flag 我们已经定义了两个命名空间 Li 和 Han,并在其中各自声明flag变量,使用的时候则需要分别用域解析操作符指明此时用的flag变量是谁定义出来的flag变量,是小韩还是小李定义的。 除了直接使用域解析操作符,还可以采用using声明(using declaration),例如: using Li::flag; flag = 0; //使用小李定义的变量flag Han::flag = false; //使用小韩定义的变量flag 在代码的开头用using声明了Li::flag,其含义是using声明以后的程序中如果出现未指明的flag时,则使用Li::flag,但是若要使用小韩定义的flag,则仍需要Han::flag。 using声明不仅仅可以针对命名空间中的一个变量,也可以用于声明整个命名空间,例如: using namespace Li; flag = 0; //使用小李定义的变量flag Han::flag = false; //使用小韩定义的变量flag 如果命名空间Li中还定义了其他的变量,则同样具有flag变量的效果,在using声明后,若出现未具体指定命名空间的命名冲突变量,则默认采用Li命名空间中的变量。 命名空间内部不仅可以声明或定义变量,对于其它能在命名空间以外声明或定义的实体,同样也都能在命名空间内部进行声明或定义,例如变量的声明或定义、函数的声明或定义、typedef等都可以出现在命名空间中。 下面我们来看一个简单的C++程序的示例: #include<iostream> using namespace std; int main(){ cout<<"hello world!"<<endl; return 0; } 这是一个简单的C++程序hello world示例,在程序中采用了using声明命名空间std,using namespace std; 这一语句涵盖了std命名空间中的所有标识符,而该命名空间包含C++所有标准库。头文件iostream文件中定义的所有变量、函数等都位于std命名空间中,每次使用iostream中的变量或函数都需要在前面加上std::是非常麻烦的一件事,为此可直接用using声明将std中的所有变量或函数等都声明出来。 如果不用using namespace std;这一语句,则程序应该像下面这样: #include<iostream> int main(){ std::cout<<"hello world!"<<std::endl; return 0; } 这样看起来是相当麻烦的,如果在某次使用iostream中变量或函数时漏掉std则会导致为定义标识符错误。 C++语言是以C语言为基础的,它继承了所有的C语言函数库,但C++对这些标准库都重新命名了。标准C头文件(如math.h)重命名为cmath,去掉头文件的.h,并在前面加上c。因此在C++中如需使用math.h头文件则可以按照如下方式使用。复制纯文本新窗口 #include<cmath> using namespace std;
布尔类型(bool)是C++新增的一种基本数据类型。在标准的C语言中并未定义bool类型,如果需要使用bool类型,程序员可以通过宏定义来自定义一个bool类型,定义语句如下: #define bool int #define false 0 #define true 1 也就是将int型定义为bool型,将int型的0和1两个值分别定义为bool类型的两个值true和false。 但是在C++中则不需要这么麻烦,C++中对bool类型已经做出了定义。 bool类型是C++语言基本数据结构之一,在80x86处理器上编译器gcc 4.8.1和Visual C++ 2012给bool类型变量分配1个字节长度。bool类型取值范围仅有两个值:true和false。在做逻辑运算时,默认非零即为ture。 定义bool类型变量也与其他基本数据类型变量的定义类似,如下所示: bool flag = true;
[TOC] 20世纪80年代,AT&T Bell(贝尔)实验室的Bjarne Stroustrup博士及其同事在C语言的基础上成功开发出C++语言。C++语言是一种混合型语言,它保留了C语言所有的优点,同时又增添了面向对象的编程机制,我们可以将C++语言视为C语言的改进和扩展。 基于C语言开发的C++语言兼容C语言,因此用C语言编写的程序基本上可以不做改动地用于C++。相对于C语言,C++语言对C语言的功能做了一定的扩充,同时增添了面向对象编程机制。引入面向对象编程机制,主要是为了提高开发效率。 C++能用来干什么 下图是2014年3月份世界编程语言排行榜,在该排行榜中,C++语言位列第4,从这个排名中我们也可以看出C++语言应用是非常广泛的。C++语言可以用于应用软件开发、娱乐游戏开发、多媒体音视频处理、网络通信和智能识别等。 1) 软件开发 操作系统可以分为两块:内核以及内核以外的一些应用程序。内核用于控制最底层的硬件设备,而应用程序则是用于完成一系列的任务。应用程序是通过调用系统提供的接口(如windows API)操作硬件来实现一系列的功能。 要想从事应用软件开发,除了需要掌握基本的C++语法以外,还需要对windows系统及其他系统提供的API或SDK有一定的了解。与之相对应的岗位主要有软件开发工程师、算法工程师、架构工程师等。 2) 游戏开发 掌握了C++基本语法之后,开发游戏也依然是一个不错的选择,目前工业级别的3D游戏引擎仍然是用C或C++编写的。 虽然以个人能力无法去完成一个庞大的网络游戏,但是从简单开始,编写一些小游戏,然后逐渐深入,循序渐进并最终加入大型游戏开发团队还是非常好的一个选择。与之相应的就业岗位主要有游戏开发工程师、游戏引擎架构工程师等。 3) 多媒体开发 目前多媒体技术同样渗入到人们的日常生活中,音视频已经成为人们获取信息的一个非常重要的手段。音视频在传输过程中都是经过压缩并且按照一定规则打包过的。视频的编码技术从最开始的H.261到如今的H.265,经历了30多年的发展,而且实现代码全部是由C或C++实现。 最新的HEVC编码标准就是由C++代码实现,对此感兴趣的话在学完C++语法后,可以去ITU(国际电信联盟)官网去下载源码查看。与之相应的就业岗位有图像算法工程师、视频编码研发工程师、音视频转码工程师等。 4) 人工智能 人工智能、机器学习等方向也少不了C或C++语言的身影。虽然人工智能距离我们还有些远,但随着科技的飞速进步,将来能实现也未可知。 需要强调的是虽然C++语言可以从事的方向非常广泛,但是仅仅掌握C++语法是远远不够的,上述的应用领域C++语言是基础,进入这些领域还需要进一步深入学习相关领域的专业知识。千里之行,始于足下!下面我们将一一介绍C++的基本语法,以期能够帮助大家熟练掌握C++,为今后的发展奠定良好基础。
C++是由C语言发展而来,保留了C语言的所有语法,增加了面向对象的机制,并且与C语言兼容,用C语言编写的程序可以不加修改地用于C++。因此本教程针对有C语言基础的读者编写,不再赘述C语言的语法,直接讲解C++的新增内容。 如果你不了解C语言,请先学习C语言教程。 C++ 虽然增加了面向对象的机制,但是不像Java(Java强制开发人员使用面向对象编程),你仍然可以编写“纯”面型过程的代码,因此C++是一种功能强大的混合型的编程语言。 面向对象程序设计,是针对开发较大规模的程序而提出来的,目的是提高软件开发的效率(不是执行效率)。 不要把面向对象和面向过程对立起来,面向对象和面向过程不是矛盾的,而是各有用途、互为补充的。 C++的语法比较复杂,初学者可能有点吃力,但是请一定要坚持,一旦熟悉了,你会发现非常的好用和灵活。 C++的语法也影响了后来的Java,Java在设计的时候有意模仿和简化了C++语法,以便让C++开发人员可以很容易地切换到Java。
工欲善其事必先利其器 [toc] 要看项目源代码必须有一个优秀的代码编辑器,就我知道支持代码跳转的编辑器有source insight, sublime, geany, vim。 source insight 不用配置,一般在windows系统用; sublime 有个monokai主题比较漂亮; geany 功能比较简单,只支持在已打开文件代码里跳转; 默认的vim 体验感比较差,配置后就很强大了,下图; vim 的基本操作请自行百度,为师不教这个。下面是vim配置内容。 配置代码提示功能 最重要的是安装vim和python sudo apt-get update #更新软件源 sudo apt-get clang #安装clang sudo apt-get cmake #安装cmake sudo apt-get install vim #安装vim sudo apt-get install python python-dev #安装Python相关 接下来正式安装YCM sudo apt-get install vim-addon-manager #这应该是一个vim的插件管理器 sudo apt-get install vim-youcompleteme #安装YCM vim-addons install youcompleteme #将YCM加入addons管理器中 直接上我的配置,将这个复制到用户目录下,命名为 .vimrc 即可。 syntax on set nocompatible set tags+=~/.vim/systags set nu set autoindent set shiftwidth=4 set ignorecase set cindent set hls is set hlsearch set ts=4 set history=100 set syntax=c highlight Function cterm=bold,underline ctermbg=red ctermfg=green highlight TabLine term=underline cterm=bold ctermfg=9 ctermbg=4 highlight TabLineSel term=bold cterm=bold ctermbg=Red ctermfg=yellow highlight Pmenu ctermbg=darkred highlight PmenuSel ctermbg=red ctermfg=yellow set ruler colorscheme desert let g:winManagerWindowLayout='FileExplorer|TagList|BufExplorer' let g:winManagerWidth=35 "let Tlist_Auto_Open=1 let Tlist_Ctags_Cmd = '/usr/bin/ctags' let Tlist_Show_One_File = 1 let Tlist_Exit_OnlyWindow = 1 let Tlist_Use_Left_Window = 1 "F7 NERDTree map <F7> :NERDTreeToggle<CR> imap <F7> <ESC>:NERDTreeToggle<CR> map <F8> :WMToggle<CR> imap <F8> <ESC>:WMToggle<CR> 这样就配置好代码提示功能,可自行体验一下。 配置代码主题 配置系统默认主题 首先:在终端输入 # $ ls /usr/share/vim/vim73/colors wu_being@UbuntuKylin1704:~/Github/leveldb$ ls /usr/share/vim/vim80/colors/ blue.vim delek.vim evening.vim morning.vim peachpuff.vim shine.vim zellner.vim darkblue.vim desert.vim industry.vim murphy.vim README.txt slate.vim default.vim elflord.vim koehler.vim pablo.vim ron.vim torte.vim wu_being@UbuntuKylin1704:~/Github/leveldb$ wu_being@UbuntuKylin1704:~/Github/leveldb$ 查看是否有上面提到的某些配色,所有配色均是以.vim结束的,如果有的话,再输入: $ cd ~/ 到用户主目录,然后输入 $ vim .vimrc 创建配置文件,将vim的内容设置如下: set nu colorscheme desert syntax on 即配置好desert.vim这种主题方案了,如果想使用其他主题方案,就把desert换成对应的名字就ok啦~~~ 下面开始愉快的使用vim编程吧!!! 配置molokai主题 sublime text的配色主题比较绚丽多彩,今天浏览网页时发现一款vim的molokai配色,它是基于textmate的monokai主题, 和sublime text 的默认主题monokai很像,喜欢使用sublime text的童鞋可以试试。 molokai.vim代码如下: " Vim color file " " Author: Tomas Restrepo <tomas@winterdom.com> " " Note: Based on the monokai theme for textmate " by Wimer Hazenberg and its darker variant " by Hamish Stuart Macpherson " hi clear set background=dark set t_Co=256 "告知molokai,终端支持256色。 if version > 580 " no guarantees for version 5.8 and below, but this makes it stop " complaining hi clear if exists("syntax_on") syntax reset endif endif let g:colors_name="molokai" if exists("g:molokai_original") let s:molokai_original = g:molokai_original else let s:molokai_original = 0 endif hi Boolean guifg=#AE81FF hi Character guifg=#E6DB74 hi Number guifg=#AE81FF hi String guifg=#E6DB74 hi Conditional guifg=#F92672 gui=bold hi Constant guifg=#AE81FF gui=bold hi Cursor guifg=#000000 guibg=#F8F8F0 hi Debug guifg=#BCA3A3 gui=bold hi Define guifg=#66D9EF hi Delimiter guifg=#8F8F8F hi DiffAdd guibg=#13354A hi DiffChange guifg=#89807D guibg=#4C4745 hi DiffDelete guifg=#960050 guibg=#1E0010 hi DiffText guibg=#4C4745 gui=italic,bold hi Directory guifg=#A6E22E gui=bold hi Error guifg=#960050 guibg=#1E0010 hi ErrorMsg guifg=#F92672 guibg=#232526 gui=bold hi Exception guifg=#A6E22E gui=bold hi Float guifg=#AE81FF hi FoldColumn guifg=#465457 guibg=#000000 hi Folded guifg=#465457 guibg=#000000 hi Function guifg=#A6E22E hi Identifier guifg=#FD971F hi Ignore guifg=#808080 guibg=bg hi IncSearch guifg=#C4BE89 guibg=#000000 hi Keyword guifg=#F92672 gui=bold hi Label guifg=#E6DB74 gui=none hi Macro guifg=#C4BE89 gui=italic hi SpecialKey guifg=#66D9EF gui=italic hi MatchParen guifg=#000000 guibg=#FD971F gui=bold hi ModeMsg guifg=#E6DB74 hi MoreMsg guifg=#E6DB74 hi Operator guifg=#F92672 " complete menu hi Pmenu guifg=#66D9EF guibg=#000000 hi PmenuSel guibg=#808080 hi PmenuSbar guibg=#080808 hi PmenuThumb guifg=#66D9EF hi PreCondit guifg=#A6E22E gui=bold hi PreProc guifg=#A6E22E hi Question guifg=#66D9EF hi Repeat guifg=#F92672 gui=bold hi Search guifg=#FFFFFF guibg=#455354 " marks column hi SignColumn guifg=#A6E22E guibg=#232526 hi SpecialChar guifg=#F92672 gui=bold hi SpecialComment guifg=#465457 gui=bold hi Special guifg=#66D9EF guibg=bg gui=italic hi SpecialKey guifg=#888A85 gui=italic if has("spell") hi SpellBad guisp=#FF0000 gui=undercurl hi SpellCap guisp=#7070F0 gui=undercurl hi SpellLocal guisp=#70F0F0 gui=undercurl hi SpellRare guisp=#FFFFFF gui=undercurl endif hi Statement guifg=#F92672 gui=bold hi StatusLine guifg=#455354 guibg=fg hi StatusLineNC guifg=#808080 guibg=#080808 hi StorageClass guifg=#FD971F gui=italic hi Structure guifg=#66D9EF hi Tag guifg=#F92672 gui=italic hi Title guifg=#ef5939 hi Todo guifg=#FFFFFF guibg=bg gui=bold hi Typedef guifg=#66D9EF hi Type guifg=#66D9EF gui=none hi Underlined guifg=#808080 gui=underline hi VertSplit guifg=#808080 guibg=#080808 gui=bold hi VisualNOS guibg=#403D3D hi Visual guibg=#403D3D hi WarningMsg guifg=#FFFFFF guibg=#333333 gui=bold hi WildMenu guifg=#66D9EF guibg=#000000 if s:molokai_original == 1 hi Normal guifg=#F8F8F2 guibg=#272822 hi Comment guifg=#75715E hi CursorLine guibg=#3E3D32 hi CursorColumn guibg=#3E3D32 hi LineNr guifg=#BCBCBC guibg=#3B3A32 hi NonText guifg=#BCBCBC guibg=#3B3A32 else hi Normal guifg=#F8F8F2 guibg=#1B1D1E hi Comment guifg=#465457 hi CursorLine guibg=#293739 hi CursorColumn guibg=#293739 hi LineNr guifg=#BCBCBC guibg=#232526 hi NonText guifg=#BCBCBC guibg=#232526 end " " Support for 256-color terminal " if &t_Co > 255 hi Boolean ctermfg=135 hi Character ctermfg=144 hi Number ctermfg=135 hi String ctermfg=144 hi Conditional ctermfg=161 cterm=bold hi Constant ctermfg=135 cterm=bold hi Cursor ctermfg=16 ctermbg=253 hi Debug ctermfg=225 cterm=bold hi Define ctermfg=81 hi Delimiter ctermfg=241 hi DiffAdd ctermbg=24 hi DiffChange ctermfg=181 ctermbg=239 hi DiffDelete ctermfg=162 ctermbg=53 hi DiffText ctermbg=102 cterm=bold hi Directory ctermfg=118 cterm=bold hi Error ctermfg=219 ctermbg=89 hi ErrorMsg ctermfg=199 ctermbg=16 cterm=bold hi Exception ctermfg=118 cterm=bold hi Float ctermfg=135 hi FoldColumn ctermfg=67 ctermbg=16 hi Folded ctermfg=67 ctermbg=16 hi Function ctermfg=118 hi Identifier ctermfg=208 hi Ignore ctermfg=244 ctermbg=232 hi IncSearch ctermfg=193 ctermbg=16 hi Keyword ctermfg=161 cterm=bold hi Label ctermfg=229 cterm=none hi Macro ctermfg=193 hi SpecialKey ctermfg=81 hi MatchParen ctermfg=16 ctermbg=208 cterm=bold hi ModeMsg ctermfg=229 hi MoreMsg ctermfg=229 hi Operator ctermfg=161 " complete menu hi Pmenu ctermfg=81 ctermbg=16 hi PmenuSel ctermbg=244 hi PmenuSbar ctermbg=232 hi PmenuThumb ctermfg=81 hi PreCondit ctermfg=118 cterm=bold hi PreProc ctermfg=118 hi Question ctermfg=81 hi Repeat ctermfg=161 cterm=bold hi Search ctermfg=253 ctermbg=66 " marks column hi SignColumn ctermfg=118 ctermbg=235 hi SpecialChar ctermfg=161 cterm=bold hi SpecialComment ctermfg=245 cterm=bold hi Special ctermfg=81 ctermbg=232 hi SpecialKey ctermfg=245 hi Statement ctermfg=161 cterm=bold hi StatusLine ctermfg=238 ctermbg=253 hi StatusLineNC ctermfg=244 ctermbg=232 hi StorageClass ctermfg=208 hi Structure ctermfg=81 hi Tag ctermfg=161 hi Title ctermfg=166 hi Todo ctermfg=231 ctermbg=232 cterm=bold hi Typedef ctermfg=81 hi Type ctermfg=81 cterm=none hi Underlined ctermfg=244 cterm=underline hi VertSplit ctermfg=244 ctermbg=232 cterm=bold hi VisualNOS ctermbg=238 hi Visual ctermbg=235 hi WarningMsg ctermfg=231 ctermbg=238 cterm=bold hi WildMenu ctermfg=81 ctermbg=16 hi Normal ctermfg=252 ctermbg=233 hi Comment ctermfg=59 hi CursorLine ctermbg=234 cterm=none hi CursorColumn ctermbg=234 hi LineNr ctermfg=250 ctermbg=234 hi NonText ctermfg=250 ctermbg=234 end 使用方法: 将molokai.vim文件放到~/.vim/colors/文件夹下即可。 在~/.vimrc 中配置 :colorscheme molokai 则默认使用此配色。 现在可以用vim打开任意代码享受这个主题吧! 配置代码间跳转--ctags 安装ctags sudo apt install ctags 在程序项目主目录(想实现代码间跳转的目录)输入ctags -R,会在当前生成一个tags文件。 wu_being@UbuntuKylin1704:~$ cd Github/leveldb/ wu_being@UbuntuKylin1704:~/Github/leveldb$ ctags -R wu_being@UbuntuKylin1704:~/Github/leveldb$ ls -ltr 总用量 1952 ... -rw-rw-r-- 1 wu_being wu_being 1287 11月 14 12:57 test.cpp -rw-r--r-- 1 wu_being wu_being 291705 11月 14 13:19 tags wu_being@UbuntuKylin1704:~/Github/leveldb$ wu_being@UbuntuKylin1704:~/Github/leveldb$ pwd /home/wu_being/Github/leveldb wu_being@UbuntuKylin1704:~/Github/leveldb$ 在vimrc文件末行添加: set tags+=/home/wu_being/Github/leveldb/tags 注意:必须使用“+=”,并且两边不能有空格。 使用方法: Ctrl + ] Ctrl + o 在Linux环境下任意目录下的程序文件里的函数,要实现跳转到相关定义代码进行查看,只需要将vim光标移动到函数名或宏定义名称上,使用快捷键“Ctrl+]”,即可跳转定义中的函数或宏定义的地方进行查看,有多个要跳转的路径时会在vim下边出现几行选项,直接输入数字加回车可以进行对应的函数或宏定义选择;要想返回上一级函数或宏定义,只需要使用快捷键“Ctrl+o”,即可跳会上次的查看的函数。 vim多窗口使用技巧 1、打开多个窗口 打开多个窗口的命令以下几个: 横向切割窗口 :new+窗口名(保存后就是文件名) :split+窗口名,也可以简写为:sp+窗口名 纵向切割窗口名 :vsplit+窗口名,也可以简写为:vsp+窗口名 2、关闭多窗口 可以用:q!,也可以使用:close,最后一个窗口不能使用close关闭。使用close只是暂时关闭窗口,其内容还在缓存中,只有使用q!、w!或x才能真能退出。 :tabc 关闭当前窗口 :tabo 关闭所有窗口 3、窗口切换 :ctrl+w+j/k,通过j/k可以上下切换,或者:ctrl+w加上下左右键,还可以通过快速双击ctrl+w依次切换窗口。 4、窗口大小调整 纵向调整 :ctrl+w + 纵向扩大(行数增加) :ctrl+w - 纵向缩小 (行数减少) :res(ize) num 例如::res 5,显示行数调整为5行 :res(ize)+num 把当前窗口高度增加num行 :res(ize)-num 把当前窗口高度减少num行 横向调整 :vertical res(ize) num 指定当前窗口为num列 :vertical res(ize)+num 把当前窗口增加num列 :vertical res(ize)-num 把当前窗口减少num列 5、给窗口重命名 :f file 6、vi打开多文件 vi a b c :n 跳至下一个文件,也可以直接指定要跳的文件,如:n c,可以直接跳到c文件 :e# 回到刚才编辑的文件 7、文件浏览 :Ex 开启目录浏览器,可以浏览当前目录下的所有文件,并可以选择 :Sex 水平分割当前窗口,并在一个窗口中开启目录浏览器 :ls 显示当前buffer情况 8、vi与shell切换 :shell 可以在不关闭vi的情况下切换到shell命令行 :exit 从shell回到vi 设置代码折叠 1. 折叠方式 可用选项来设定折叠方式: 可在Vim 配置文件中设置 set fdm=XXX可直接在文件中使用注释调用vim命令 / vim: set fdm=XXX: / 有6种方法来选定折叠: manual 手工定义折叠 indent 更多的缩进表示更高级别的折叠 expr 用表达式来定义折叠 syntax 用语法高亮来定义折叠 diff 对没有更改的文本进行折叠 marker 对文中的标志折叠 注意,每一种折叠方式不兼容,如不能既用expr又用marker方式,我主要轮流使用indent和marker方式进行折叠。 使用时,用 set fdm=marker 命令来设置成marker折叠方式(fdm是foldmethod的缩写)。要使每次打开vim时折叠都生效,则在.vimrc文件中添加设置,如添加:set fdm=syntax,就像添加其它的初始化设置一样。 2. 折叠命令 选取了折叠方式后,我们就可以对某些代码实施我们需要的折叠了,由于我使用indent和marker稍微多一些,故以它们的使用为例:如果使用了indent方式,vim会自动的对大括号的中间部分进行折叠,我们可以直接使用这些现成的折叠成果。 在可折叠处(大括号中间): zc 折叠 zC 对所在范围内所有嵌套的折叠点进行折叠 zo 展开折叠 zO 对所在范围内所有嵌套的折叠点展开 [z 到当前打开的折叠的开始处。 ]z 到当前打开的折叠的末尾处。 zj 向下移动。到达下一个折叠的开始处。关闭的折叠也被计入。 zk 向上移动到前一折叠的结束处。关闭的折叠也被计入。 当使用marker方式时,需要用标计来标识代码的折叠,系统默认是{{{和}}},最好不要改动 我们可以使用下面的命令来创建和删除折叠: zf 创建折叠,比如在marker方式下: zf56G,创建从当前行起到56行的代码折叠; 10zf或10zf+或zf10↓,创建从当前行起到后10行的代码折叠。 10zf-或zf10↑,创建从当前行起到之前10行的代码折叠。 在括号处zf%,创建从当前行起到对应的匹配的括号上去((),{},[],<>等)。 zd 删除 (delete) 在光标下的折叠。 仅当 'foldmethod' 设为 "manual" 或 "marker" 时有效。 zD 循环删除 (Delete) 光标下的折叠,即嵌套删除折叠。 仅当 'foldmethod' 设为 "manual" 或 "marker" 时有效。 zE 除去 (Eliminate) 窗口里“所有”的折叠。 仅当 'foldmethod' 设为 "manual" 或 "marker" 时有效。 Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢!《工欲善其事必先利其器 —— 配置vim》: https://yq.aliyun.com/articles/247401/ 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
[TOC] 回顾上一篇文章《[leveldb] 初步探索 leveldb》的样例代码,是不是发现有个类比例简单:leveldb::Status,你发现它有status.ok()和status.ToString()方法。那怎么找到Status类的定义和成员方法的实现呢? 1、 第一步:把相关代码找出来 1-1 用grep 大法过滤内容 我们知道C++的类一般是这样定义的:class Status {...},我们grep在当前目前递归-r .全词匹配-w和半词匹配都搜不到,最后grep "Status {"出来了,并显示代码所在行数-n。 wu_being@UbuntuKylin1704:~/Github/leveldb$ grep "class Status" -rnw . wu_being@UbuntuKylin1704:~/Github/leveldb$ grep "class Status" -rn . wu_being@UbuntuKylin1704:~/Github/leveldb$ grep "Status{" -rn . wu_being@UbuntuKylin1704:~/Github/leveldb$ grep "Status {" -rn . ./include/leveldb/status.h:22:class LEVELDB_EXPORT Status { wu_being@UbuntuKylin1704:~/Github/leveldb$ 这个就是Status类定义的头文件: ./include/leveldb/status.h:22:class LEVELDB_EXPORT Status { 1-2 用find 大法找到文件 我们发现上面grep大法连文件名都过滤出来,下面用find大法通过文件名匹配到相关文件,找到一个Status类方法实现的文件./util/status.cc。 wu_being@UbuntuKylin1704:~/Github/leveldb$ wu_being@UbuntuKylin1704:~/Github/leveldb$ find . -name *status.* ./util/status.cc ./util/status.o ./out-static/util/status.o ./include/leveldb/status.h ./out-shared/util/status.o wu_being@UbuntuKylin1704:~/Github/leveldb$ 2、 第二步:RTFSC (Read the fucking source code ) wu_being@UbuntuKylin1704:~/Github/leveldb$ wu_being@UbuntuKylin1704:~/Github/leveldb$ gedit include/leveldb/status.h & [2] 3936 wu_being@UbuntuKylin1704:~/Github/leveldb$ gedit util/status.cc [2]+ 已完成 gedit include/leveldb/status.h wu_being@UbuntuKylin1704:~/Github/leveldb$ 2-1 include/leveldb/status.h #ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_ #define STORAGE_LEVELDB_INCLUDE_STATUS_H_ #include <string> #include "leveldb/export.h" #include "leveldb/slice.h" namespace leveldb { class LEVELDB_EXPORT Status { public: // Create a success status. Status() : state_(NULL) { } ~Status() { delete[] state_; } // Copy the specified status. Status(const Status& s); void operator=(const Status& s); // Return a success status. static Status OK() { return Status(); } // Return error status of an appropriate type. static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) { return Status(kNotFound, msg, msg2); } ... // Returns true iff the status indicates success. bool ok() const { return (state_ == NULL); } // Returns true iff the status indicates a NotFound error. bool IsNotFound() const { return code() == kNotFound; } ... // Return a string representation of this status suitable for printing. // Returns the string "OK" for success. // status.cc std::string ToString() const; private: // OK status has a NULL state_. Otherwise, state_ is a new[] array // of the following form: // state_[0..3] == length of message // state_[4] == code // state_[5..] == message const char* state_; enum Code { kOk = 0, kNotFound = 1, kCorruption = 2, kNotSupported = 3, kInvalidArgument = 4, kIOError = 5 }; Code code() const { return (state_ == NULL) ? kOk : static_cast<Code>(state_[4]); } // status.cc Status(Code code, const Slice& msg, const Slice& msg2); static const char* CopyState(const char* s); }; inline Status::Status(const Status& s) { state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); } inline void Status::operator=(const Status& s) { // The following condition catches both aliasing (when this == &s), // and the common case where both s and *this are ok. if (state_ != s.state_) { delete[] state_; state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); } } } // namespace leveldb #endif // STORAGE_LEVELDB_INCLUDE_STATUS_H_ 2-1-1 类Status公有成员变量和方法 构造函数 public: // Create a success status. Status() : state_(NULL) { } // Copy the specified status. Status(const Status& s); void operator=(const Status& s); inline Status::Status(const Status& s) { state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); } inline void Status::operator=(const Status& s) { // The following condition catches both aliasing (when this == &s), // and the common case where both s and *this are ok. if (state_ != s.state_) { delete[] state_; state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); } } 析构函数 ~Status() { delete[] state_; } 2-1-2 类Status私有成员变量和方法 私有成员变量 下面这个state_设计很不好调试,在后面的CopyState方法就是了,没有手工调试配制state_。 // OK status has a NULL state_. Otherwise, state_ is a new[] array // of the following form: // state_[0..3] == length of message // state_[4] == code // state_[5..] == message const char* state_; enum Code { kOk = 0, kNotFound = 1, kCorruption = 2, kNotSupported = 3, kInvalidArgument = 4, kIOError = 5 }; 私有成员方法 Code code() const { return (state_ == NULL) ? kOk : static_cast<Code>(state_[4]); } // status.cc Status(Code code, const Slice& msg, const Slice& msg2); static const char* CopyState(const char* s); 2-2 util/status.cc #include <stdio.h> #include "port/port.h" #include "leveldb/status.h" namespace leveldb { const char* Status::CopyState(const char* state) { uint32_t size; memcpy(&size, state, sizeof(size)); char* result = new char[size + 5]; memcpy(result, state, size + 5); return result; } Status::Status(Code code, const Slice& msg, const Slice& msg2) { assert(code != kOk); const uint32_t len1 = msg.size(); const uint32_t len2 = msg2.size(); const uint32_t size = len1 + (len2 ? (2 + len2) : 0); char* result = new char[size + 5]; memcpy(result, &size, sizeof(size)); result[4] = static_cast<char>(code); memcpy(result + 5, msg.data(), len1); if (len2) { result[5 + len1] = ':'; result[6 + len1] = ' '; memcpy(result + 7 + len1, msg2.data(), len2); } state_ = result; } std::string Status::ToString() const { if (state_ == NULL) { return "OK."; } else { char tmp[30]; const char* type; switch (code()) { case kOk: type = "OK..."; break; case kNotFound: type = "NotFound: "; break; ... default: snprintf(tmp, sizeof(tmp), "Unknown code(%d): ", static_cast<int>(code())); type = tmp; break; } std::string result(type); uint32_t length; memcpy(&length, state_, sizeof(length)); result.append(state_ + 5, length); return result; } } } // namespace leveldb Status::CopyState // OK status has a NULL state_. Otherwise, state_ is a new[] array // of the following form: // state_[0..3] == length of message // state_[4] == code // state_[5..] == message const char* Status::CopyState(const char* state) { uint32_t size; //sizeof(size)为4 memcpy(&size, state, sizeof(size));//把state前面4个length of message字符给size char* result = new char[size + 5]; memcpy(result, state, size + 5); return result; } Status::ToString() const std::string Status::ToString() const { if (state_ == NULL) { return "OK."; } else { char tmp[30]; const char* type; switch (code()) { case kOk: type = "OK..."; break; case kNotFound: type = "NotFound: "; break; ... default: snprintf(tmp, sizeof(tmp), "Unknown code(%d): ", static_cast<int>(code())); type = tmp; break; } std::string result(type); uint32_t length; memcpy(&length, state_, sizeof(length)); result.append(state_ + 5, length); return result; } } 私有构造函数 Status::Status Status::Status(Code code, const Slice& msg, const Slice& msg2) { assert(code != kOk); const uint32_t len1 = msg.size(); const uint32_t len2 = msg2.size(); const uint32_t size = len1 + (len2 ? (2 + len2) : 0); char* result = new char[size + 5]; memcpy(result, &size, sizeof(size)); result[4] = static_cast<char>(code); memcpy(result + 5, msg.data(), len1); if (len2) { result[5 + len1] = ':'; result[6 + len1] = ' '; memcpy(result + 7 + len1, msg2.data(), len2); } state_ = result; } Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢!《[leveldb] 学习leveldb第一个类Status》: https://yq.aliyun.com/articles/241407/ 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
[TOC] 1、 leveldb 简介 leveldb 是 Google 用 C++ 开发的一个快速的 键值对存储数据库(持久化KV单机数据库),提供从字符串键到字符串值的有序映射,具有很高的随机写,顺序读/写性能,但是随机读的性能很一般,也就是说,LevelDB很适合应用在查询较少,而写很多的场景。 LevelDB应用了 LSM (Log Structured Merge) 策略,lsm_tree对索引变更进行延迟及批量处理,并通过一种类似于归并排序的方式高效地将更新迁移到磁盘,降低索引插入开销,关于LSM,本文在后面也会简单提及。 根据LevelDB官方网站的描述,LevelDB的特点和限制如下: 1-1 特点 1、key和value都是任意长度的字节数组; 2、entry(即一条K-V记录)默认是按照key的字典顺序存储的,当然开发者也可以重载这个排序函数; 3、提供的基本操作接口:Put()、Delete()、Get()、Batch(); 4、支持批量操作以原子操作进行; 5、可以创建数据全景的snapshot(快照),并允许在快照中查找数据; 6、可以通过前向(或后向)迭代器遍历数据(迭代器会隐含的创建一个snapshot); 7、自动使用Snappy压缩数据; 8、可移植性; 1-2 限制 1、非关系型数据模型(NoSQL),不支持sql语句,也不支持索引; 2、一次只允许一个进程访问一个特定的数据库; 3、没有内置的C/S架构,但开发者可以使用LevelDB库自己封装一个server; LevelDB本身只是一个lib库,在源码目录make编译即可,然后在我们的应用程序里面可以直接include leveldb/include/db.h头文件 2、 leveldb 安装 2-1 下载 leveldb wu_being@UbuntuKylin1704:~/Github/leveldb$ git clone https://github.com/google/leveldb 2-2 编译 leveldb wu_being@UbuntuKylin1704:~/Github/leveldb$ cd leveldb/ wu_being@UbuntuKylin1704:~/Github/leveldb$ make 编译的动态库和静态库分别在 out-shared,out-static 下: wu_being@UbuntuKylin1704:~/Github/leveldb$ ls leveldb/out-shared/libleveldb.so.1.20 wu_being@UbuntuKylin1704:~/Github/leveldb$ ls leveldb/out-static/libleveldb.a 2-3 安装 leveldb 只有动态库需要安装,如果静态库在编译后直接链接即可。 (动态库静态库请看文章后来更多链接) # cp leveldb header file wu_being@UbuntuKylin1704:~/Github/leveldb$ sudo cp -r /leveldb/include/ /usr/include/ # cp lib to /usr/lib/ wu_being@UbuntuKylin1704:~/Github/leveldb$ sudo cp /leveldb/out-shared/libleveldb.so.1.20 /usr/lib/ # create link wu_being@UbuntuKylin1704:~/Github/leveldb$ sudo ln -s /usr/lib/libleveldb.so.1.20 /usr/lib/libleveldb.so.1 wu_being@UbuntuKylin1704:~/Github/leveldb$ sudo ln -s /usr/lib/libleveldb.so.1.20 /usr/lib/libleveldb.so # update lib cache wu_being@UbuntuKylin1704:~/Github/leveldb$ sudo ldconfig 查看动态库安装是否成功 wu_being@UbuntuKylin1704:~/Github/leveldb$ ls /usr/lib/libleveldb.so* # 显示下面 3 个文件即安装成功 /usr/lib/libleveldb.so.1.20 /usr/lib/libleveldb.so.1 /usr/lib/libleveldb.so 3、 leveldb 使用 我们的 leveldb目录下编写一个 test.cpp 来测试我们的 leveldb。将key1对应的value值,移到key2对应的值。。 #include <iostream> #include <string> #include <assert.h> #include "leveldb/db.h" using namespace std; int main(void) { leveldb::DB *db; leveldb::Options options; options.create_if_missing = true; // options.error_if_exists = true; // open leveldb::Status status = leveldb::DB::Open(options,"/tmp/testdb2", &db); assert(status.ok()); string key1 = "name1"; string key2 = "name2"; string value = "wuchengbing12"; // write key1 status = db->Put(leveldb::WriteOptions(), key1, value); assert(status.ok()); // read key1 status = db->Get(leveldb::ReadOptions(), key1, &value); assert(status.ok()); cout<<value<<endl; // write key2 status = db->Put(leveldb::WriteOptions(), key2, value); assert(status.ok()); // delete key1 status = db->Delete(leveldb::WriteOptions(), key1); assert(status.ok()); status = db->Get(leveldb::ReadOptions(),key2, &value); // assert(status.ok()); if(!status.ok()) { cerr<<key2<<" "<<status.ToString()<<endl; } else { cout<<key2<<"==="<<value<<"==="<<status.ToString()<<endl; } // close delete db; return 0; } 3-1 编译 - 静态链接 wu_being@UbuntuKylin1704:~/Github/leveldb$ cp out-static/libleveldb.a ./ wu_being@UbuntuKylin1704:~/Github/leveldb$ g++ test.cpp -o test ./libleveldb.a -lpthread -Iinclude 3-2 编译 - 动态链接 wu_being@UbuntuKylin1704:~/Github/leveldb$ g++ test.cpp -o test -lpthread -lleveldb -Iinclude 3-3 运行结果 # 输出值为 a,说明成功存储和获取 wu_being@UbuntuKylin1704:~/Github/leveldb$ ./test wuchengbing12 name2===wuchengbing12===OK wu_being@UbuntuKylin1704:~/Github/leveldb$ # 查看数据库 wu_being@UbuntuKylin1704:~/Github/leveldb$ ls /tmp/testdb2/ -l 总用量 24 -rw-r--r-- 1 wu_being wu_being 166 11月 13 13:14 000005.ldb -rw-r--r-- 1 wu_being wu_being 106 11月 13 13:14 000006.log -rw-r--r-- 1 wu_being wu_being 16 11月 13 13:14 CURRENT -rw-r--r-- 1 wu_being wu_being 0 11月 13 13:14 LOCK -rw-r--r-- 1 wu_being wu_being 310 11月 13 13:14 LOG -rw-r--r-- 1 wu_being wu_being 57 11月 13 13:14 LOG.old -rw-r--r-- 1 wu_being wu_being 83 11月 13 13:14 MANIFEST-000004 wu_being@UbuntuKylin1704:~/Github/leveldb$ 4、 代码解释 4-1 打开一个数据库实例 一个leveldb数据库有一个对应一个文件系统目录的名字。该数据库的所有内容都存储在这个目录下。下面的代码描述了怎样打开一个数据库或者建立一个新的数据库。 #include <assert.h> #include "leveldb/db.h" leveldb::DB* db; leveldb::Options options; options.create_if_missing = true; //如果要打开的数据库不存在就创建新的 leveldb::Status status = leveldb::DB::Open(options,"/tmp/testdb", &db); assert(status.ok()); 如果打开已存在数据库的时候,需要抛出错误。将以下代码插在leveldb::DB::Open方法前面: options.error_if_exists = true; 4-2 对数据库的简单读、写操作 LevelDB提供了Put,Delete和Get三个方法对数据库进行修改和查询。例如,下面的代码片段描述了怎样将key1对应的value值,移到key2对应的值。 std::string value; leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value); if(s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value); if(s.ok()) s = db->Delete(leveldb::WriteOptions(), key1); 4-3 关闭数据库 在对数据库进行了一系列的操作之后,需要对数据库进行关闭。该操作比较简单: ... open the db as described above... ... do something with db ... delete db; 5、 更多链接 C语言的静态库与共享库使用:http://blog.csdn.net/u014134180/article/details/78335274 Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢!《[leveldb] 初探 leveldb》: https://yq.aliyun.com/articles/241407/ 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
[TOC] 建议是多研究一些好项目,不要成为“语言学家”! 从一篇朋友圈说起 我发了一条朋友圈,打算把C++所有语法过一遍。发现自己之前学C渣渣学得太渣了,老是和 C语言的混在一起理解,发现 C++保留的结构体 struct 就和 C语言的有区别: C/C++语言的结构体的成员变量默认是公有的,而 C++的类成员变量默认是私有的; C++结构体可以声明定义函数,而 C语言结构里只是声明为指针函数,并在外部实现; 这里不要讨论C艹的地方,以后有机会在发出相关的介绍文章吧! 这条朋友圈被一个研究数据库底层的牛逼师兄留意到了,评论: “我的建议是多研究一些好项目,不要成为语言学家”。 牛逼师兄的指导 吴兵:有没有比较小一点的开源项目推荐给我学习研究研究。 师兄:那我就推荐一个吧,MySQL。可以研究一下mysql with rocksdb :https://github.com/facebook/mysql-5.6 。你可以研究一下其中的myrocks —— rocksdb引擎。 吴兵:文档还是mysql官网的吗 师兄:rocksdb引擎的 文档你就只能从github上看了 吴兵:哦哦哦 师兄: 学习c++的话,在以前的话,leveldb是很推荐的, jeff dean写的,代码写得很规范。 rocksdb是facebook基于leveldb去二次开发的,现在大家都是在用rocksdb而不会直接去用leveldb 吴兵:google的leveldb吗 师兄:都是一脉相传的东西,可以认为是当前最值得研究的C++项目了 吴兵:哦哦哦, 好的 师兄:leveldb有些源码剖析的东西,可以快速扫一下。 用git clone下来,看下git log,还有对应的work log,研究它的演化过程。最重要的是要理解它的深层思维,懂得它为什么这个样子和怎么发展到这个样子 。 师兄:停留在研究语法和简单的代码,进步很慢其实也没啥用。 吴兵:是啊,看这种提交log吗 师兄:嗯。但是leveldb你看git log 都很早了,现在rocksdb源码还是很活跃的, 每个月都新增很多代码, 像这种新增一个功能进去 师兄:git log里有个网址, https://github.com/facebook/rocksdb/pull/2202 ,像这个里就有讨论代码怎么写 吴兵:怎么看到这个提交修改了那些代码 师兄:github上每一个提交都能看到对应的修改, 更方便的当然是git clone到本地,我一般会用可视化的git工具来看代码修改, linux下的话像gitg,win下的话像source tree 吴兵:gitk吗 师兄:挺多工具的,看代码的话,对着git log看是最快能理解的 吴兵:这个 pull request是分支请求合并到这个干支的吗 师兄:嗯,合并到了原来项目的主分支了 吴兵:很多项目都有这个文件.travis.yml,.gitignore。这是做什么的 师兄: gitignore是git用来过滤那些不用作版本管理的文件,比较 .o .so .a这种编译代码时会产生的文件,另一个文件我就不知道了 师兄: 搞这种大型项目就是要以点带面,慢慢地就能搞懂了, 如果一下看不懂,也不要轻易放弃,继续多看多琢磨。 吴兵: [GitHub - google/leveldb at f67e15e50f392625b4097caf22e8be1b0fe96013 : https://github.com/google/leveldb/tree/f67e15e50f392625b4097caf22e8be1b0fe96013] 师兄:什么问题? 吴兵:这个第一次提交交了那么多代码,是实现一个demo吧。 这个demo原理怎么研究[捂脸] 师兄:这个是它第一次搬到github上的代码,看它的git log上写着另一个网址,是原先在googlecode上的。你可以先搜一下level的源码分析看看,看个大概就行。 吴兵:喔喔 师兄:理解一下 lsm树,理解 compaction,还有 version set。 吴兵:version set是数据结构吗 师兄:不是。 吴兵:什么玩意 师兄: version set version edit是leveldb用来管理sst文件版本的一套机制,如果我没记错的话。不要贪多,你可以就研究一下version set的代码 吴兵:编译后出来了out-shard和out-static目录,要怎么使用这个数据库 师兄: leveldb并不算是个数据库,它只是kv存储系统。 师兄:别的系统可以用它来做存储引擎。 通过动态链接或者静态链接的方式集成进来如果你写程序,需要存放数据,你可以用leveldb来存。然后编译你的代码的时候将leveldb的静态库或者动态库引进来就行了。 师兄:facebook将leveldb做了很多扩展,然后用作了mysql的一个存储引擎。 吴兵:https://www.zhihu.com/question/38933764/answer/80312254 。sugar,原来 当作库来调用 师兄:在我们的txsql里,我就把rocksdb打包成.so,可以运行时选择是否装载。 吴兵:这是我 总结的C语言的静态库与共享库 http://blog.csdn.net/u014134180/article/details/78335274 得到C++之父的真传 只看图,不说话。 Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢!《大神对话录——leveldb》: https://yq.aliyun.com/articles/241361/
1 翻转思路 1-1 整体的思路 1-2 详细的思路 2 代码实现 3 运行结果 写个翻转链表算法,刚开始想到一个不错的思路。这个思路运行效率不低,时间复杂度为O(n);可以不用分配额外的节点空间,空间复杂度为O(0)。现在把思路整理一下,并实现代码,测试运行结果。 1、 翻转思路 1-1 整体的思路 用一个while顺序遍历这个链表,然后把遍历到每个节点插入到链表头部。 1-2 详细的思路 蓝色箭头即赋值符号,比如在第2个结点的操作: step 2.1:front指针前移一位; step 2.2:把head节点的next值(即指向节点1的地址)赋给节点2; step 2.3:把节点2的地址赋给head节点的next; step 2.4:back指针前移一位; while遍历条件可根据back不为空,即while(back); 2、 代码实现 #include<stdio.h> // NULL #include<stdlib.h> // malloc #define ElemType int typedef struct LNode{ // 定义单链表结点类型 ElemType data; // 数据域 struct LNode *next; // 指针域 }LNode, *LinkList; // LinkList相当于LNode*,即:struct LNode* // 尾插法建立单链表L LinkList listcreat_fromtail(LinkList L); // 翻转链表L的算法 LinkList reverse_linklist(LinkList L); // 把节点Node插入链表L头部 LinkList insert_head(LinkList L, LNode * Node); // 输出链表L元素, flag=0为链表翻转前,flag=1为链表翻转后 void print_linklist(LinkList L, int flag); int main(int argc, char *argv[]) { LinkList L; // 尾插法建立单链表L L = listcreat_fromtail(L); // 输出翻转前(flag=0)链表元素 print_linklist(L, 0); // 翻转链表L L = reverse_linklist(L); // 输出翻转后(flag=1)链表元素 print_linklist(L, 1); return 0; } // 翻转链表L的算法 LinkList reverse_linklist(LinkList L) { LNode *back, *front; back = L->next; // step 0.1, init L->next = NULL; // step 0.2, init while(back){ front = back->next; // step x.1 L = insert_head(L, back);// step x.2, step x.3 back = front; // step x.4 } //back = front = NULL; // for secure return L; } // 把节点Node插入链表L头部 LinkList insert_head(LinkList L, LNode * node) { node->next = L->next; // step x.2 L->next = node; // step x.3 return L; } // 输出链表L元素, flag=0为链表翻转前,flag=1为链表翻转后 void print_linklist(LinkList L, int flag) { printf(flag ? "翻转后:\n" : "翻转前:\n"); printf("单链表元素个数:%d, 分别是:", L->data); for(LNode* N = L->next; N; N = N->next){ printf("%d ",N->data); } puts("\n"); } //尾插法建立单链表L LinkList listcreat_fromtail(LinkList L) { int len, data; LNode *r; L = (LinkList)malloc(sizeof(LNode)); L->data = 0; L->next = NULL; // L->data为链表长度 r = L; // r为表尾指针 printf("请输入插法建立单链表长度:"); scanf("%d", &len); printf("请逐个输入链表元素:"); while(len--){ scanf("%d",&data); LNode *s=(LNode*)malloc(sizeof(LNode)); s->data = data; s->next = NULL; r->next = s; r = r->next; L->data++; // 链表长度+1 } return L; } 3、 运行结果 huashidazhongbeitushuguandeiMac-2:Wu_Being duzhe$ vim reverse_linklist.c huashidazhongbeitushuguandeiMac-2:Wu_Being duzhe$ gcc reverse_linklist.c huashidazhongbeitushuguandeiMac-2:Wu_Being duzhe$ ./a.out 请输入插法建立单链表长度:5 请逐个输入链表元素:1 2 3 4 5 翻转前: 单链表元素个数:5, 分别是:1 2 3 4 5 翻转后: 单链表元素个数:5, 分别是:5 4 3 2 1 huashidazhongbeitushuguandeiMac-2:Wu_Being duzhe$ ./a.out 请输入插法建立单链表长度:3 请逐个输入链表元素:1 2 3 4 翻转前: 单链表元素个数:3, 分别是:1 2 3 翻转后: 单链表元素个数:3, 分别是:3 2 1 huashidazhongbeitushuguandeiMac-2:Wu_Being duzhe$ Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《翻转链表算法和实现》: http://blog.csdn.net/u014134180/article/details/78423589 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
中断Interruption 异常Exception 在操作系统中引入核心态和用户态这两种工作状态后,就需要考虑这两种状态之间如何切换。操作系统内核工作在核心态,而用户程序工作在用户态。但系统不允许用户程序实现核心态的功能,而它们又必须使用这些功能。因此,需要在核心态建立一些“门”,实现从用户态进入核心态。在实际操作系统中,CPU运行上层程序时唯一能进入这些“门”的途径就是通过中断或异常。 当中断或异常发生时,运行用户态的CPU会立即进入核心态,这是通过硬件实现的(例如,用一个特殊寄存器的一位来表示CPU所处的工作状态,0表示核心态,1表示用户态。若要进入核心态,只需将该位置0即可)。 中断是操作系统中非常重要的一个概念,对一个运行在计算机上的实用操作系统而言,缺少了中断机制,将是不可想象的。 中断(Interruption) 中断(Interruption),也称外中断,指来自CPU执行指令以外的事件的发生,如: 设备发出的I/O结束中断,表示设备输入/输出处理已经完成,希望处理机能够向设备发下一个输入/输出请求,同时让完成输入/输出后的程序继续运行。 时钟中断,表示一个固定的时间片已到,让处理机处理计时、启动定时运行的任务等。 这一类中断通常是与当前程序运行无关的事件,即它们与当前处理机运行的程序无关。 异常(Exception) 异常(Exception),也称内中断、例外或陷入(Trap),指源自CPU执行指令内部的事件,如: 程序的非法操作码、地址越界、算术溢出、虚存系统的缺页以及专门的陷入指令等引起的事件。 对异常的处理一般要依赖于当前程序的运行现场,而且异常不能被屏蔽,一旦出现应立即处理。关于内中断和外中断的联系与区别如图1-2所示。 图1-2 内中断和外中断的联系与区别 Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《中断和异常的概念》: http://blog.csdn.net/u014134180/article/details/78418428 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
RTFSC – Read The Fucking Source Code Fucking在这里难道完全就是语气词?当然不是这么肤浅。 RTFSC 一词 生动形象的体现了阅读源代码的艰难和重要性。 Linux的鼻祖Linus Torvalds在回答有人提出的Minix的一个问题时,所说的第一句话就是”Read The Fucking Source Code”,这就是RTFSC的来由。 ——https://baike.baidu.com/item/RTFSC/2503453 D:\Wu_Being\CP_Code\CP_Code\kernel\ D:\Wu_Being\CP_Code\CP_Code\linux-3.18.48\drivers\ D:\Wu_Being\CP_Code\CP_Code\linux-3.18.48\drivers\input\ D:\Wu_Being\CP_Code\CP_Code\A_O-linux-3.18.48\drivers\input\fingerprint\ xxx_defconfig Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《Makefile和Kconfig配置项目——Input子系统fingerprint》: http://blog.csdn.net/u014134180/article/details/78394721 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
结构体struct 1 结构体的基本知识 2 结构体与函数 3 结构体数组 4 自引用结构体 枚举变量enum 联合体union 位字段 1 一般的方法定义屏蔽吗 2 用位字段来定义屏蔽吗 自定义类型typedef 字节对齐 pragma pachx 按x个字节对齐 1.结构体struct 1.1 结构体的基本知识 #include <stdio.h> struct point{ int x; int y; }p1, p2, p3; struct point pt; struct point pt2 = {300, 400}; struct point pt3 = {.x = 500}; struct rect { struct point pt1; struct point pt2; }; struct rect screen; int main() { printf("pt2.x = %d, pt2.y = %d\n", pt2.x, pt2.y); printf("pt3.x = %d, pt3.y = %d\n", pt3.x, pt3.y); double dist, sqrt(); dist = sqrt((double)pt2.x*pt2.x + (double)pt2.y*pt2.y); printf("dist = %lf \n", dist); printf("screen.pt2.x = %d \n", screen.pt2.x); return 0; } huashidazhongbeitushuguan5deiMac:wufile duzhe$ vim struct.c huashidazhongbeitushuguan5deiMac:wufile duzhe$ gcc struct.c huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out pt2.x = 300, pt2.y = 400 pt3.x = 500, pt3.y = 0 dist = 500.000000 screen.pt2.x = 0 huashidazhongbeitushuguan5deiMac:wufile duzhe$ 1.2 结构体与函数 传递结构体的每个成员变量; 传递整个机构体; 传递指向结构体的指针; #include <stdio.h> struct point{int x; int y;}; struct rect { struct point pt1; struct point pt2; }; struct rect screen; struct point midlle; struct point makepoint(int, int); int main() { #define XMAX 300 #define YMAX 400 screen.pt1 = makepoint(0, 0); screen.pt2 = makepoint(XMAX, YMAX); struct point origin = {30}, *pp; origin.y = 40; //origin = {.x = 30, .y = 40}; //error //origin = {30, 40}; //error pp = &origin; printf("origin: .x,.y is (%d, %d)\n", origin.x, origin.y); printf("origin: (*pp).x is (%d, %d)\n", (*pp).x, (*pp).y); printf("origin: pp->x is (%d, %d)\n\n", pp->x, pp->y); return 0; } struct point makepoint(int x, int y) { struct point temp; temp.x = x; temp.y = y; return temp; } /* struct point addpoint(struct point p1, struct point p2) { p1.x += p2.x; p1.y += p2.y; return p1; } int pt_in_rect(struct point p, struct rect r) { return p.x >= r.pt1.x && p.x <= r.pt2.x && p.y >= r.pt1.y && p.y <= r.pt2.y; } #define min(a,b) ((a) < (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b)) // 矩形规范化 struct rect canon_rect(struct rect r) { struct rect temp; temp.pt1.x = min(r.pt1.x, r.pt2.x); temp.pt1.y = min(r.pt1.y, r.pt2.y); temp.pt2.x = max(r.pt1.x, r.pt2.x); temp.pt2.y = max(r.pt1.y, r.pt2.y); return temp; } */ struct rect r, *rp = &r; //下面四个等价的 r.pt1.x; rp->pt1.x; (r.pt1).x; (rp->pt1).x; //anonymous struct struct {int len; char * str; }*p, pn[]={{10,"ah",},20,"ABC", 30,"123",}; p = &pn; //struct3.c:7:3: warning: incompatible pointer types assigning to 'struct (anonymous struct at struct3.c:6:1) *' from 'struct (anonymous struct at struct3.c:6:1) (*)[3]' [-Wincompatible-pointer-types] p = pn; //下面两个等价的 ++p->len; //11 ++(p->len); //12 //指向下个对象 (++p)->len; //20 (p++)->len; //20 (p)->len; //30 //字符串的操作 p = pn; *p->str 同 *(p->str) // just a char. %c: a *p->str++ 同 *s++ // %c: a ,->h //(*p->str)++ 对象++,导致段错误 (*p->str)+1 //i *p->str + 2 //j *p++->str //%c: h 先取str值,后指向下个对象 *p->str //%c: A p->str //%s: ABC ++(p->str)//%s: BC 1.3 结构体数组 struct key{ char *word; int count; }keytab[NKEYS]; struct key keytab2[MKEYS]; struct key{ char *word; int count; }keytab[]={"AUTO", 0, "char", 2, {"cha", 3,},}; 1.4 自引用结构体 struct tnode{ char *word; int count; struct tnode *left; struct tnode *right; }; 2.枚举变量enum 例子1 #include <stdio.h> int main() { enum boolean{NO, YES}b; enum boolean bb = YES; printf("enum NO: %d\n", NO); printf("boolean b: %d \n",b); printf("boolena b = %d, bb = %d \n",b = NO, ++bb); printf("sizeof(b): %lu, sizeof(enum boolean): %lu \n", sizeof(b), sizeof(enum boolean)); return 0; } huashidazhongbeitushuguan5deiMac:wufile duzhe$ vim enum.c huashidazhongbeitushuguan5deiMac:wufile duzhe$ gcc enum.c huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out enum NO: 0 boolean b: 1790791734 boolena b = 0, bb = 2 sizeof(b): 4, sizeof(enum boolean): 4 huashidazhongbeitushuguan5deiMac:wufile duzhe$ 例子2 // 不同枚举中的名字必须互不相同(有区分大小写),同一枚举不同名字的值可以相同 enum escapes{ BELL = '\a', BELL2= '\a', BACKSPACE = '\b', TAB = '\t', tab = '\t', NEWLINE = '\n', VTAB = '\v', RETURN = '\r', }; 例子3 // 比#define有优势就是常量值就自动生成的,如:FEB = 2, MAR = 3 ... enum months{JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV ,DEC }; 3.联合体union 例子1 #include <stdio.h> //共享同一内存,大小取决于最大成员 union { int a; char c; }u = {10}; //初始化第一个成员,而且只能初始化一个 int main() { printf("1 sizeof(u): %lu\n", sizeof(u)); printf("%d, %c\n", u.a, u.c); u.c = 'a'; printf("2 sizeof(u): %lu\n", sizeof(u)); printf("%d, %c\n", u.a, u.c); return 0; } huashidazhongbeitushuguan5deiMac:wufile duzhe$ vim union.c huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out 1 sizeof(u): 4 10, 2 sizeof(u): 4 97, a 好处:不确定类型时,或者兼容多种类型。 union u_tag{ int ival; float fval; char *sval; }u; if(utype == INT){ printf("%d\n", u.ival); }else if(utype == FLOAT){ printf("%f\n", u.fval); }else if(utype == STRING){ printf("%s\n", u.sval); }else{ printf("bad type %d in utype\n", utype); } 嵌套在结构体 struct { char *name; int flags; int utype; union{ int ival; float fval; char *sval; }u; }symtab[NSYM]; //引用成员ival symtab[i].u.ival; //引用sval第一个字符 *symtab[i].u.sval; symtab[i].u.sval[0]; 例子2 #include <stdio.h> union { int a; float b; char c; }u = {10}; int main() { printf("1 sizeof(u): %lu\n", sizeof(u)); printf("%d, %f, %c\n", u.a, u.b, u.c); u.b = 3.5f; printf("2 sizeof(u): %lu\n", sizeof(u)); printf("%d, %f, %c\n", u.a, u.b, u.c); return 0; } huashidazhongbeitushuguan5deiMac:wufile duzhe$ gcc union.c huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out 1 sizeof(u): 4 10, 0.000000, 2 sizeof(u): 4 1080033280, 3.500000, huashidazhongbeitushuguan5deiMac:wufile duzhe$ 例子2-2 printf("1 sizeof(u): %lu\n", sizeof(u)); printf("%d, %f, %c\n", u.a, u.b, u.c); u.b = 3.5f; printf("2 sizeof(u): %lu\n", sizeof(u)); printf("%d, %f, %c\n", u.a, u.b, u.c); u.c = 'a'; printf("3 sizeof(u): %lu\n", sizeof(u)); printf("%d, %f, %c\n", u.a, u.b, u.c); huashidazhongbeitushuguan5deiMac:wufile duzhe$ vim union.c huashidazhongbeitushuguan5deiMac:wufile duzhe$ gcc union.c huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out 1 sizeof(u): 4 10, 0.000000, 2 sizeof(u): 4 1080033280, 3.500000, 3 sizeof(u): 4 1080033377, 3.500023, a 例子2-3 printf("1 sizeof(u): %lu\n", sizeof(u)); printf("%d, %f, %c\n", u.a, u.b, u.c); u.c = 'a'; printf("3 sizeof(u): %lu\n", sizeof(u)); printf("%d, %f, %c\n", u.a, u.b, u.c); huashidazhongbeitushuguan5deiMac:wufile duzhe$ vim union.c huashidazhongbeitushuguan5deiMac:wufile duzhe$ gcc union.c huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out 1 sizeof(u): 4 10, 0.000000, 2 sizeof(u): 4 10, 0.000000, 3 sizeof(u): 4 97, 0.000000, a huashidazhongbeitushuguan5deiMac:wufile duzhe$ 4.位字段 4.1 一般的方法定义屏蔽吗 //宏定义 #define KEYWORD 01 #define EXTERNAL 02 #define STATIC 04 //枚举变量 enum{KEYWORD = 01, EXTERNAL = 02, STATIC = 04}; flags |= EXTERNAL | STATIC; flags &= ~(EXTERNAL | STATIC); if((flags & (EXTERNAL|STATIC) ) == 0)... 4.2 用位字段来定义屏蔽吗 unsigned int 最大是4字节*8位 = 32位,sizeof是总的字节数,且为4的倍数(0,4,8,16…). #include <stdio.h> //定义了3个一位宽度的字段 struct{ //33 = 32 + 1 (bit)= 4 up byte = 8 type. unsigned int is_keyword : 1; unsigned int is_extern : 1; unsigned int is_static : 1; unsigned int err : 8; unsigned int add :16; //unsigned int err2 :64; //bit.c:10:18: error: width of bit-field 'err2' (64 bits) exceeds width of its type (32 bits) int :1; //无名字段 int :4; int :0; int :1; }flags, *p = &flags;//字段不是数组,没有地址,不能用&引用,但结构体有地址可以用&引用。 int main() { printf("sizeof(flags): %lu\n", sizeof(flags)); printf("%d, %d\n", flags.is_extern, flags.is_static); flags.is_extern = flags.is_static = 0; printf("%d, %d\n", flags.is_extern, flags.is_static); flags.is_extern = flags.is_static = 1; printf("%d, %d\n", flags.is_extern, flags.is_static); flags.is_extern = flags.is_static = 2; printf("%d, %d\n", flags.is_extern, flags.is_static); flags.is_extern = flags.is_static = 3; printf("%d, %d\n", flags.is_extern, flags.is_static); if(flags.is_extern == 0 && flags.is_static == 0);//...; flags.add = 65525; flags.err = 255; printf("sizeof(flags): %lu\n", sizeof(flags)); return 0; } huashidazhongbeitushuguan5deiMac:wufile duzhe$ vim bit.c huashidazhongbeitushuguan5deiMac:wufile duzhe$ gcc bit.c bit.c:25:43: warning: implicit truncation from 'int' to bitfield changes value from 2 to 0 [-Wbitfield-constant-conversion] flags.is_extern = flags.is_static = 2; ^ ~ bit.c:27:43: warning: implicit truncation from 'int' to bitfield changes value from 3 to 1 [-Wbitfield-constant-conversion] flags.is_extern = flags.is_static = 3; ^ ~ bit.c:30:50: warning: if statement has empty body [-Wempty-body] if(flags.is_extern == 0 && flags.is_static == 0);//...; ^ bit.c:30:50: note: put the semicolon on a separate line to silence this warning 3 warnings generated. huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out sizeof(flags): 8 0, 0 0, 0 1, 1 0, 0 1, 1 sizeof(flags): 8 huashidazhongbeitushuguan5deiMac:wufile duzhe$ 5.自定义类型typedef 可移植性 容易理解 typedef int Length; Length len, maxlen; Lenght *length[]; typedef char* String; String p, lineptr[MAXLINES], alloc(int); int strcmp(String, String); p = (String) malloc(1024); typedef struct tnode *Treeptr; typedef struct tnode{ char *word; int count; Treeptr *left; Treeptr *right; }Treenode; Treeptr talloc(void) { return (Treeptr)malloc(sizeof(Treenode)); } // PFI是一个指向函数的指针 typedef int (*PFI)(char*, char*); PFI strcmp, strcpy; 6.字节对齐 以最长(系统一次读的长度)为基本单位。 struct A{ int a;//4/ char b;//1 short c;//2 //1/ }a; sizeof(a) = sizeof(struct A) = 8; struct B{ char a;//4 int b;//4/ short c;//4 }b; sizeof(b) = sizeof(struct B) = 12; 32位系统一次4字节,long long 8位读两次。sizeof是以%d: int 返回。 {char 4, LL 4+4, int 4} = 16 {char 4, int 4, short4} = 12 {LL 4+4, char 4, int 4} = 16 {LL 4+4, char 4 short } = 12 64位系统一次8字节,没long时,一次读4字节。sizeof是以%lu: long unsigned int 返回。LL和L都是8个字节。 //一次读8字节 { LL 8 , char 8 int } = 16 {char 8, LL 8 , int 8 } = 24 //一次读4字节 {char 4,int 4, short 4} = 12 {char 4 short , int 4 } = 8 pragma pach(x) 按x个字节对齐 #pragma pach(2) struct c{char 2; int 2+2; short 2;} = 8 #pragma pach(1) struct c{char 1; int 4; short 2;} = 7 Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《结构体struct、枚举enum、联合体union、位字段、自定义类型typedef、字节对齐》: http://blog.csdn.net/u014134180/article/details/78335328 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
标准C库提供了4个内存管理函数:malloc、calloc、realloc和free。 bug1 调用free释放p指向的内存块之后,p就是一个悬挂指针——指向逻辑上不存在的内存的指针。如果引用这个悬挂指针,会导致不可预见的错误。 ElemType* p = (ElemType*)malloc(sizeof(ElemType) * NUM); ... free(p);// p = NULL; ... *p = "..."; bug2 释放空闲内存,破坏内存管理函数所用的数据结构。 ElemType* p = (ElemType*)malloc(sizeof(ElemType) * NUM); ... free(p); ... free(p); bug3 释放并非malloc、calloc或realloc分配的内存。 ElemType buf[20], *p; if(n >= sizeof(buf){ p = (ElemType*)malloc(sizeof(ElemType) * NUM); }else{ p = buf; } ... free(p); bug4 1、没有考虑内存分配不成功的情况。如果分配失败应返回NULL; 2、使用后没有释放内存,多次调用会导致内存泄漏; void itoa(int n, char *buf, int size){ char *p = malloc(43); sprintf(p, "%d", n); if(strlen(p) >= size-1){//如果数字个数大于size-1时,用*填充。 while(--size > 0){ *buf++ = '*'; } *buf = '\0'; }else{ strcpy(buf, p); } } 初学者更容易犯下面的错误。itoa试图返回buf的内容,但itoa返回后,buf已经被清空了。 char *itoa(int n){ char buf[43]; sprintf(buf, "%d", n); return buf; } Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《C语言内存分配管理常见bug》: http://blog.csdn.net/u014134180/article/details/78335307 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
1库的概念 2静态库 2-1 静态库的概念 2-2 静态库的创建 2-2-1 静态库创建的命令 2-2-2 静态库创建的准备工作 2-2-3 创建静态库的例子 2-3 静态库的使用 2-3-1 静态库使用的命令 2-3-2 静态库使用的例子 3共享库动态链接库 3-1 共享库的概念 3-2 共享库的创建 3-2-1 共享库的创建命令 3-2-2 共享库的创建例子 3-3 共享库的使用 3-3-1 共享库的使用命令 3-3-2 共享库的使用例子 4不使用库的方法 1、库的概念 函数库是由系统建立的且有一定功能的函数集合。库中存放函数的名称和对应的目标代码,以及连接过程中所需的重定位信息,但是库中对应的函数的源代码一般是不可见的,而对应的头文件中可以看到它的对外接口(函数原型)。 Linux中标准的C函数库放置在/usr/lib下,以文件形式存放。用户也可以根据自己的所需建立自己的用户函数库。函数库分为静态库(.a)和共享库(.so,ShareObj),共享库在windows环境也叫动态链接库(.dll)。 2、静态库 2-1 静态库的概念 静态库是一些.o目标文件的集合,一般以.a形式结尾。静态库在程序链接阶段使用,链接器将程序要用到的函数从库中提取出来,并整合到程序中,程序运行不再使用静态库了。由于每个程序要用到函数都从库提取并整合在一起,所以可执行文件夹会比较大。 2-2 静态库的创建 2-2-1 静态库创建的命令 ar rcs lib库文件名.a 目标文件1 目标文件2 ... 目标文件n r:表示将.o目标文件加入到静态库中; c:表示创建静态库; s:表示生产索引; 2-2-2 静态库创建的准备工作 wu_being@UbuntuKylin1704:~/Code/C$ mkdir lib_test wu_being@UbuntuKylin1704:~/Code/C$ cd lib_test/ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ l wu_being@UbuntuKylin1704:~/Code/C/lib_test$ mkdir bin include obj src wu_being@UbuntuKylin1704:~/Code/C/lib_test$ l bin/ include/ obj/ src/ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ vim src/mymath_test.c wu_being@UbuntuKylin1704:~/Code/C/lib_test$ cat -n src/mymath_test.c 1 #include <stdio.h> 2 #include "mymath.h" 3 4 int main() 5 { 6 printf("My Pi: %lf"\n, my_pi()); 7 return 0; 8 } 9 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ vim include/mymath.h wu_being@UbuntuKylin1704:~/Code/C/lib_test$ cat -n include/mymath.h 1 #ifndef __MYMATH_H__ 2 #define __MYMATH_H__ 3 4 double my_pi(void); 5 6 #endif wu_being@UbuntuKylin1704:~/Code/C/lib_test$ vim src/mymathfun.c wu_being@UbuntuKylin1704:~/Code/C/lib_test$ cat -n src/mymathfun.c 1 2 double my_pi(void) 3 { 4 return 3.14159; 5 } 2-2-3 创建静态库的例子 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ mkdir lib wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -o obj/mymathfun.o -c src/mymathfun.c wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ar rcs lib/libmymathfun.a obj/mymathfun.o wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ls lib/ libmymathfun.a wu_being@UbuntuKylin1704:~/Code/C/lib_test$ 或者 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ar rcs lib/libmymathfun.a src/mymathfun.c wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ls lib/ libmymathfun.a wu_being@UbuntuKylin1704:~/Code/C/lib_test$ 2-3 静态库的使用 2-3-1 静态库使用的命令 gcc -o 可执行文件 调用者的C源文件.c -Ldir -l库文件名 或者 gcc -o 调用者的目标文件.o -c 调用者的C源文件.c gcc -o 可执行文件 调用者的目标文件.o -Ldir -l库文件名 -Ldir:表示指定库文件所在的路径中,默认在库路径在/usr/lib目录下; -lname:表示库目录的库文件libname.a或libname.so。如果库文件不是以lib开头,如hello.a,只能用用hello.a,不能用-lhello。 删除静态库文件不会影响到可执行文件的运行。 2-3-2 静态库使用的例子 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -o bin/mymathfun_test src/mymath_test.c -Iinclude -Llib -lmymathfun wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ./bin/mymathfun_test My Pi: 3.141590 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -o obj/mymath_test.o -c src/mymath_test.c -Iinclude wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -o bin/mymathfun_test obj/mymath_test.o -Iinclude -Llib -lmymathfun wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ./bin/mymathfun_test My Pi: 3.141590 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ 3、共享库(动态链接库) 3-1 共享库的概念 共享库即动态链接库,在linux中以.so(share object)为后缀,在windows中以.dll为后缀。程序开始启动运行时,加载所需的函数,程序运行时也需要共享库的支持。共享库链接出来的文件比静态库要小得多。Linux中所有标准的共享库存放在/usr/lib目录中。 3-2 共享库的创建 3-2-1 共享库的创建命令 gcc -shared -fPCI -o lib库文件名.so 目标文件1,目标文件2,...,目标文件n -shared:表示要创建共享库; -fpci或-fPCI:表示创建产生独立目标代码,具体应用取决于平台; 3-2-2 共享库的创建例子 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -o obj/mymathfun.o -c src/mymathfun.c wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -shared -fPCI -o lib/libmymathfun2.so obj/mymathfun.o gcc: error: unrecognized command line option ‘-fPCI’; did you mean ‘-fPIC’? wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -shared -fPIC -o lib/libmymathfun2.so obj/mymathfun.o wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -shared -fpic -o lib/libmymathfun2.so obj/mymathfun.o wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -shared -fPCI -o lib/libmymathfun2.so obj/mymathfun.o gcc: error: unrecognized command line option ‘-fPCI’; did you mean ‘-fPIC’? wu_being@UbuntuKylin1704:~/Code/C/lib_test$ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ls lib/ libmymathfun.a libmymathfun2.so wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ls lib/ -l 总用量 12 -rw-r--r-- 1 wu_being wu_being 1684 10月 24 17:31 libmymathfun.a -rwxr-xr-x 1 wu_being wu_being 8152 10月 24 20:59 libmymathfun2.so wu_being@UbuntuKylin1704:~/Code/C/lib_test$ 3-3 共享库的使用 3-3-1 共享库的使用命令 gcc -o 可执行文件 调用者的C源文件.c -Ldir -l库文件名 或者 gcc -o 调用者的目标文件.o -c 调用者的C源文件.c gcc -o 可执行文件 调用者的目标文件.o -Ldir -l库文件名 运行可执行文件提示找汪以库文件的解决方案 sudo cp libmymathfun2.so /usr/lib export LD_LIBRARY_PATH=库文件目录 删除静态库文件会影响到可执行文件的运行!(提示找不到库文件) 3-3-2 共享库的使用例子 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -shared -fPIC -o lib/libmymathfun2.so src/mymathfun.c wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -o bin/mymathfun_test2 src/mymath_test.c -Iinclude -Llib -lmymathfun2 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ./bin/mymathfun_test2 ./bin/mymathfun_test2: error while loading shared libraries: libmymathfun2.so: cannot open shared object file: No such file or directory wu_being@UbuntuKylin1704:~/Code/C/lib_test$ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ sudo mv lib/libmymathfun2.so /usr/lib/ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ./bin/mymathfun_test2 My Pi: 3.141590 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ sudo rm -rf /usr/lib/libmymathfun2.so wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ls lib/ libmymathfun.a wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -shared -fPIC -o lib/libmymathfun2.so obj/mymathfun.o wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ls lib/ libmymathfun2.so libmymathfun.a wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -o bin/mymathfun_test2 -Iinclude src/mymath_test.c -Llib -lmymathfun2 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ./bin/mymathfun_test2 ./bin/mymathfun_test2: error while loading shared libraries: libmymathfun2.so: cannot open shared object file: No such file or directory wu_being@UbuntuKylin1704:~/Code/C/lib_test$ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ export LD_LIBRARY_PATH=lib wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ./bin/mymathfun_test2 My Pi: 3.141590 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ echo $LD_LIBRARY_PATH lib wu_being@UbuntuKylin1704:~/Code/C/lib_test$ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ls lib/ libmymathfun2.so libmymathfun.a wu_being@UbuntuKylin1704:~/Code/C/lib_test$ rm lib/libmymathfun2.so wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ls lib/ libmymathfun.a wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ./bin/mymathfun_test2 ./bin/mymathfun_test2: error while loading shared libraries: libmymathfun2.so: cannot open shared object file: No such file or directory wu_being@UbuntuKylin1704:~/Code/C/lib_test$ 4、不使用库的方法 test1 wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ ls mymathfun.c mymath.h mymath_test.c wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ cat -n mymath_test.c 1 #include <stdio.h> 2 #include "mymath.h" 3 4 int main() 5 { 6 printf("My Pi: %lf\n", my_pi()); 7 return 0; 8 } 9 wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ gcc mymath_test.c /tmp/ccRCzDfw.o:在函数‘main’中: mymath_test.c:(.text+0x5):对‘my_pi’未定义的引用 collect2: error: ld returned 1 exit status wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ gcc mymath_test.c mymathfun.c wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ ./a.out My Pi: 3.141593 wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ vim mymath_test.c wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ cat -n mymath_test.c 1 #include <stdio.h> 2 #include "mymath.h" 3 #include "mymathfun.c" 4 5 int main() 6 { 7 printf("My Pi: %lf\n", my_pi()); 8 return 0; 9 } 10 wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ gcc mymath_test.c wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ ./a.out My Pi: 3.141593 wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ gcc mymath_test.c mymathfun.c /tmp/ccMnE10S.o:在函数‘my_pi’中: mymathfun.c:(.text+0x0): `my_pi'被多次定义 /tmp/cc89I2rk.o:mymath_test.c:(.text+0x0):第一次在此定义 collect2: error: ld returned 1 exit status wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ test2 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -o bin/mymathfun_test src/mymath_test.c src/mymathfun.c src/mymath_test.c:2:20: fatal error: mymath.h: 没有那个文件或目录 #include "mymath.h" ^ compilation terminated. wu_being@UbuntuKylin1704:~/Code/C/lib_test$ gcc -o bin/mymathfun_test src/mymath_test.c src/mymathfun.c -Iinclude wu_being@UbuntuKylin1704:~/Code/C/lib_test$ ./bin/mymathfun_test My Pi: 3.141590 wu_being@UbuntuKylin1704:~/Code/C/lib_test$ Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《C语言的静态库与共享库》: http://blog.csdn.net/u014134180/article/details/78335274 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
1编译流程图示 2编译各阶段命令 2-1预处理阶段 2-2 编译阶段 2-3 汇编阶段 2-4 链接阶段 3例子 1、编译流程图示 我们在Linux环境下编译单个C文件时,最简单的方法是输入一条命令gcc hello.c就可以生成默认的可执行文件a.out,展开该命令可以看到实际流程如下。 (编译命令参数请看 gcc使用手册 ) 预处理阶段 -> 编译阶段 -> 汇编阶段 -> 链接阶段 2、编译各阶段命令 预处理阶段 编译阶段 汇编阶段 链接阶段 2-1预处理阶段 把.c文件预处理命令替换为对应的头文件内容,并合并成.i文件中。 gcc -E -o hello.i hello.c 预处理阶段主要处理下面四件事: 将头文件内容包含进.c源文件中; 删除注释; 宏替换; 条件编译; 2-2 编译阶段 把源文件编译成汇编语言,并生成.s文件。 gcc -S -o hello.s hello.i // or gcc -S -o hello.s hello.c 2-3 汇编阶段 把源文件汇编成机器语言,并生成.o目标文件。 gcc -o hello.o -c hello.s // or gcc -o hello.o -c hello.i gcc -o hello.o -c hello.c 2-4 链接阶段 把源文件链接成可执行文件(Linux下的文件名后缀是随便可取的,只是文件里的内容格式不变而已)。 gcc -o hello hello.o // or gcc -o hello hello.s gcc -o hello hello.i gcc -o hello hello.c gcc hello.c 3、例子 wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ ls mymathfun.c mymath.h mymath_test.c wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ cat -n mymath_test.c 1 #include <stdio.h> 2 #include "mymath.h" 3 4 int main() 5 { 6 printf("My Pi: %lf\n", my_pi()); 7 return 0; 8 } 9 wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ gcc mymath_test.c /tmp/ccRCzDfw.o:在函数‘main’中: mymath_test.c:(.text+0x5):对‘my_pi’未定义的引用 collect2: error: ld returned 1 exit status wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ gcc mymath_test.c mymathfun.c wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ ./a.out My Pi: 3.141593 wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ vim mymath_test.c wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ cat -n mymath_test.c 1 #include <stdio.h> 2 #include "mymath.h" 3 #include "mymathfun.c" 4 5 int main() 6 { 7 printf("My Pi: %lf\n", my_pi()); 8 return 0; 9 } 10 wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ gcc mymath_test.c wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ ./a.out My Pi: 3.141593 wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ gcc mymath_test.c mymathfun.c /tmp/ccMnE10S.o:在函数‘my_pi’中: mymathfun.c:(.text+0x0): `my_pi'被多次定义 /tmp/cc89I2rk.o:mymath_test.c:(.text+0x0):第一次在此定义 collect2: error: ld returned 1 exit status wu_being@UbuntuKylin1704:~/Code/C/test_cpp$ Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《C语言编译流程》: http://blog.csdn.net/u014134180/article/details/78329908 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
设置断点和恢复命令 常见命令 高级命令 查看源代码相关命令 设置工作环境相关命令 查看运行数据相关命令 gdb core 使用找段错误 gcc -g [option] [file] gdb 可执行文件 设置断点和恢复命令 1.常见命令 l(list):查看载入的文件代码,如:l 10,l main; b(break):设置断点,如:b 10,b main; info b:查看断点信息; r(run):从main运行,到断点处暂停; v 行号:从该行号开始运行; p(print) n:查看n值; n(next):单步下行; s(step):单步进入; c(continue):恢复程序的运行,执行下面程序; 2.高级命令 disable 点; enable 点; delete 点info编号; tbreak 临时断点(一次); condition 点 <条件>; ignore 点 查看源代码相关命令 list(l) <行号>/<函数名>; file [文件名] 加载文件; forword-search 正则表达式; reverse-search 正则表达式; show directories 源文件路径; disassemble 函数名:反汇编; info line 显示加载内存gdb码; 设置工作环境相关命令 set args 参数 //main(args) show args path dir 设定程序运行路径 show paths 查看程序运行路径 set envirnment var[=value] 环境变量 show envirnment var/PATH cd dir pwd shell commend 查看运行数据相关命令 print(p) 表达式、变量 x /<n/f/u> <addr> 查看内存变量内容 n:表示显示内存长度(整数) f:表示显示格式 d:十进制 x:十六进制 o:八进制 t:二进制 u: 表示显示字节数 <addr>:变量内存地址 display 表达式 display /i $pc 显示c和汇编同步 x /i $pc 程序计数器 gdb core 使用(找段错误) 打开core dump ulimit -c 默认大小为0 ulimit -c size(k) gcc -g -o 源 目文件 运行有问题产生的core文件 gdb 可执行文件 core文件 Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《gdb使用手册》: http://blog.csdn.net/u014134180/article/details/78309070 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
一般options 优化options 警告options 制作库文件options gcc [options] [filename] 编译更多例子请查看: C语言编译流程 一般options -c :只编译不链接,生成目标文件.o; -S :只编译不汇编,生成汇编码; -E :只预处理; -g :生成调试信息; -o file:生成目标文件.o或可执行文件; -v:查看gcc版本; --std=name //name: c89, c90, c99, c1x, c11; -l dir 头文件; 例子1 gcc -o bin/hello src/hello.c 例子2 gcc -o bin/hello.o -c src/hello.c gcc -o bin/hello obj/hello.o 优化options -O :即-O1,优化栈退出,线程跳转,减少代码长度和执行时间; -O2 :O1 + CPU指令调度和调整; -O3 :O2 + 循环展开,CPU特性优化; 测试优化命令 time > ./hello 警告options -ansi :支持符合ANSI的标准; -pedantic :允许发出ANSI全部警告信息; -pedantic-error :允许发出ANSI全部错误信息; -w :关闭所有警告信息; -Wall :允许发出gcc所有提供all有用报警信息; 制作库文件options -L dir :在库文件搜索路径列表中添加dir目录; -static :链接静态库; -lname :链接名为name的库文件; -shared :表明是使用共享库; Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《gcc使用手册》: http://blog.csdn.net/u014134180/article/details/78309058 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
0概要 多主机I2C总线结构 1IIC协议 1-1 空闲状态 1-2 起始信号和停止信号 1-3 应答信号 1-4 数据有效性 0、概要 IIC(IIC,I2C,inter-Integrated circuit),两线式串行总线,用于MCU和外设间的通信。 IIC只需两根线:数据线SDA和时钟线SCL。以半双工方式实现MCU和外设之间数据传输,速度最高可达400kbps,因此适用于慢速设备。 IIC设备使用7位地址(也有的是10位地址),所以在总线上最多支持127个设备,即我们看到代码的IIC地址一般不会超过0xff。 多主机I2C总线结构 注意SDA和SCL两根总线需要上拉,使总线处于空闲状态。 1、IIC协议 1-1 空闲状态 协议规定,SDA和SCL同时为高电平时,总线处于空闲状态。上拉电阻保证电平处于高电平。 1-2 起始信号和停止信号 起始信号:SCL为高电平时,SDA电平发生高到低的跳变 停止信号:SCL为高电平时,SDA电平发生低到高的跳变 1-3 应答信号 发送器每发送完一个字节(8个脉冲),在第9个脉冲间释放总线,接收器返回一个ACK信号,协议规定,低电平为有效应答,高电平为无效应答。 1-4 数据有效性 协议对有效数据进行了规定:即时钟信号为高电平期间,数据必须保持稳定;时钟信号低电平期间,数据线上的电平才允许变化。也就是说,数据在时钟信号到来前必须准备好,并保持到时钟信号的下降沿之后。 Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《学习IIC(I2C)原理》: http://blog.csdn.net/u014134180/article/details/78264817 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
如题。 这是我的主页:https://yq.aliyun.com/u/wubeing
大家好,下面是我的博客地址,欢迎访问,谢谢~ http://blog.csdn.net/u014134180
0lk 启动总体流程 1lk启动流程代码 lk app aboot abootc lk target msm8953 target_displayc lk dev gcdb display gcdb_displayc 更多相关文章: 《高通Qualcomm平台lk(light kernel)启动流程1——aboot_init()之前》: http://blog.csdn.net/u014134180/article/details/78133916 《高通Qualcomm平台lk(light kernel)启动流程2——aboot_init()》: http://blog.csdn.net/u014134180/article/details/78132580 《高通Qualcomm平台lk(light kernel)启动流程3——到高通lcm屏点亮》: http://blog.csdn.net/u014134180/article/details/78177040 《[lcm] Qualcomm Android Display Subsystem 架构》 http://blog.csdn.net/u014134180/article/details/78129502 《[lcm] Qualcomm平台的显示屏lcd驱动移植步骤》: http://blog.csdn.net/u014134180/article/details/78129499 《[lcm] Qualcomm平台兼容多显示屏lcd的方法&并从lk传输到kernel过程》: http://blog.csdn.net/u014134180/article/details/78166978 《[lcm] Qualcomm平台显示屏lcd添加I2C读取功能》: http://blog.csdn.net/u014134180/article/details/78176160 0、lk 启动总体流程 1、lk启动流程代码 lk/ app/ aboot/ aboot.c aboot_init()先判断如果是正常启动则goto normal_boot,否则就根据物理按键判断哪种启动方式,是boot_into_fastboot还是boot_into_recovery(《高通Qualcomm平台lk(light kernel)启动流程2——aboot_init()》)。 normal_boot有一步就是初始化目标屏幕,target_display_init()是lcm在lk初始化唯一的一条入口函数。 lk/ target/ msm8953/ target_display.c 在target_display_init()函数里有很重要的函数就是gcdb_display_init(),里面有 do{…} while(),这是高通原生lk LCD兼容的关键所在 。如果平台支持屏幕最大个数自动检测,msm8953支持兼容两个屏。(GCDB:Global Component Database全局组件数据库) lk/ dev/ gcdb/ display/ gcdb_display.c gcdb_display_init() gcdb_display_init()初始化pll_clk_func、power_func、bl_func等功能,初始化好之后就调用msm_display_init()函数。 gcdb_display_init ()在该函数中有一个重要的函数就是 oem_panel_select(),该函数就是根据你的hw_id 确定使用哪一款LCD,hw_id 这个是在高通的私有代码中传过来的。 (Oem_panel_select()->target/msm8953/oem_panel.c) msm_display_init() 在msm_display_init()里先Turn on panel,再Turn on backlight。 Turn on backlight(bl_func(1)) gcdb_display_init ()打开背光函数bl_func(1)指向函数mdss_dsi_bl_enable。 Turn on panel(power_func(1,…)) 屏幕上电函数power_func(1,…)指向函数mdss_dsi_panel_power。 /* add by Bert for panel exist checking 20161125 Begin */ ret = mdss_dsi_panel_reset(enable); if (ret) {dprintf(CRITICAL, "panel reset failed\n");return ret;} ret = qup_blsp_i2c_device_init(); if (ret) {dprintf(CRITICAL, "qup blsp i2c touchpanel init ret=%d\n",ret);} ret = goodix_ic_package_check(); if (ret==false) {dprintf(CRITICAL, "qup blsp i2c touchpanel check ret=%d\n",ret);} /* add by Bert for panel exist checking 20161125 End */ static struct gpio_pin enable_gpio = {"msmgpio", 61, 3, 1, 0, 1}; Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《高通Qualcomm平台lk(light kernel)启动流程3——到高通lcm屏点亮》: http://blog.csdn.net/u014134180/article/details/78177040 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
1硬件设计分析采用IC 的I2C 功能读取ID 寄存器 2ARM9 更改GPIO 配置 3LK 添加代码 4LK 阶段不接屏不亮背光 5kernel 阶段不接屏不亮背光 6kernel 阶段I2C 配置 更多相关文章: 更多相关文章: 《高通Qualcomm平台lk(light kernel)启动流程1——aboot_init()之前》: http://blog.csdn.net/u014134180/article/details/78133916 《高通Qualcomm平台lk(light kernel)启动流程2——aboot_init()》: http://blog.csdn.net/u014134180/article/details/78132580 《高通Qualcomm平台lk(light kernel)启动流程3——到高通lcm屏点亮》: http://blog.csdn.net/u014134180/article/details/78177040 《[lcm] Qualcomm Android Display Subsystem 架构》 http://blog.csdn.net/u014134180/article/details/78129502 《[lcm] Qualcomm平台的显示屏lcd驱动移植步骤》: http://blog.csdn.net/u014134180/article/details/78129499 《[lcm] Qualcomm平台兼容多显示屏lcd的方法&并从lk传输到kernel过程》: http://blog.csdn.net/u014134180/article/details/78166978 《[lcm] Qualcomm平台显示屏lcd添加I2C读取功能》: http://blog.csdn.net/u014134180/article/details/78176160 1、硬件设计分析——采用IC 的I2C 功能读取ID 寄存器 这颗IC 支持MIPI 和I2C,根据IC 厂FAE 给的datasheet,ID 寄存器只支持I2C 读取,MIPI 不可以读取该寄存器。此颗IC 的I2C 功能使用有如下几点: LK 阶段可以通过读取寄存器ID,判断IC 是否正常起来;结合ID 脚,区分一供和二供。 LK 阶段可以通过读取寄存器ID,判断是否有屏连接,控制无屏情况下,不亮背光。 Kernel 阶段实现ESD 功能,以及不接屏不亮背光。 效果调试,通过I2C 写寄存器。 设计弊端:据和IC 厂FAE 沟通,ID 寄存器是区分IC 型号;模组厂并没有和IC 厂沟通,烧写特定寄存器不同的值用区分哪家模组厂,IC 支持,如果这样,硬件设计就可以不需要LCD_ID0 这个pin 脚,还能节省一些功耗。 2、ARM9 更改GPIO 配置 Arm9 默认BLSP 配置是SPI,需要更改为I2C 模式,修改如下。 3、LK 添加代码 1、分析硬件原理图LCD 的I2C 连接在BLSP7. 2、BLSP7 对应的是BLSP2 QUP3,物理地址0x7AF7000,IRQ 是333.参考文档SP80-P3255-6B。如下图: 3、在bootable/bootloader/lk/target/msm8953/oem_panel.c 文件 i2c 的地址和寄存器ID qup_blsp_i2c_init是i2c 初始化函数,lcd_i2c_read_id 函数是读取ID 寄存器的值存储在val,根据val 的值是否是0x21,判断是否有屏连接,再根据status_id0 判断是一供还是二供。 下图是lcd_i2c_read_id函数,struct i2c_msg 存储两组数据,第一组是写ID 寄存器地址,第二组是读取的值。 4、qup_blsp_i2c_init 函数在/bootable/bootloader/lk/platform/msm_shared/i2c_qup.c init 函数主要修改gpio_config_blsp_i2c 和clock_config_blsp_i2c。 gpio_config_blsp_i2c 函数修改对应I2C 的gpio。 clock_config_blsp_i2c 函数需要配置几个clock 5、文件路径/bootable/bootloader/lk/msm8953/msm8953-clock.c 时序添加时参考本文档中的结构体 4、LK 阶段不接屏不亮背光 在oem_panel.c 文件定义全局变量lcm_exist,根据i2c 读ID 寄存器的值是否为0x21 判断是 否有连接屏幕,在/platform/msm_shared/display.c 文件中是否要打开背光。 5、kernel 阶段不接屏不亮背光 在kernel/drivers/video/msm/mdss/mdss_dsi_panel.c 文件,函数mdss_dsi_panel_bl_ctrl中去调用nt1021_read_registers 函数,根据返回值判断是否有连接屏幕,如果没有,就不level值设置为0 , 不输出pwm 。nt1021_read_registers 函数在/kernel/drivers/video/msm/msm_dba/nt51021.c 文件,是kernel 阶段i2c 驱动代码。 6、kernel 阶段I2C 配置 1、在msm8953.dtsi 添加i2c_7,对比i2c_1,修改i2c_7的寄存器。 2、在msm8953-mtp.dts 中添加&i2c_7 结构,添加使能gpio 和pinctrl。硬件设计,gpio63 控制I2C 上拉开关。 3、在msm8953-pinctrl.dtsi中针对具体的pinctrl-0,pinctrl-1 配置,参考其他gpio 配置。 4、i2c_7 的解析都在/kernel/drivers/video/msm/msm_dba/nt51021.c文件,被外部调用的函数接口有3 个,如下: 这个函数是被用来做kernel 阶段判断是否有屏连接,是否需要点亮背光。 这个函数是用来优化背光在低亮度抖动,被mdss_dsi_panel_bklt_dcs 函数调用,文件位 置/kernel/drivers/video/msm/mdss/mdss_dsi_panel.c,mdss_dsi_panel_bklt_dcs 函数是写主屏IC 产生PWM 寄存器,产生不同的pwm 控制背光亮度变化。 这个函数是用来做屏幕ESD,由于主屏ESD 还没有达到要求,软件暂未调试添加。 Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《[lcm] Qualcomm平台显示屏lcd添加I2C读取功能》: http://blog.csdn.net/u014134180/article/details/78176160 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
1如何兼容不同的LCD模组 1-1 通过LCD_ID的电平状态区分 1-2 通过IC的ID区分 1-3 通过LCD_ID和IC ID的结合区分 2LCD初始化过程 3读取LK屏的ID传输到kernel 3-1 LK把相关参数报存到pbuf 3-2 kernel获取LK保存的pbuf 3-3 解析出所用的LCD并初始化 更多相关文章: 《高通Qualcomm平台lk(light kernel)启动流程1——aboot_init()之前》: http://blog.csdn.net/u014134180/article/details/78133916 《高通Qualcomm平台lk(light kernel)启动流程2——aboot_init()》: http://blog.csdn.net/u014134180/article/details/78132580 《高通Qualcomm平台lk(light kernel)启动流程3——到高通lcm屏点亮》: http://blog.csdn.net/u014134180/article/details/78177040 《[lcm] Qualcomm Android Display Subsystem 架构》 http://blog.csdn.net/u014134180/article/details/78129502 《[lcm] Qualcomm平台的显示屏lcd驱动移植步骤》: http://blog.csdn.net/u014134180/article/details/78129499 《[lcm] Qualcomm平台兼容多显示屏lcd的方法&并从lk传输到kernel过程》: http://blog.csdn.net/u014134180/article/details/78166978 《[lcm] Qualcomm平台显示屏lcd添加I2C读取功能》: http://blog.csdn.net/u014134180/article/details/78176160 1、如何兼容不同的LCD模组 1-1 通过LCD_ID的电平状态区分 不同LCD模组的LCD_ID电平状态需不同。如下图P3590硬件原理图,通过 LCD_ID0和 LCD_ID1 pin电平状态的搭配可以兼容四类 LCD模组。 Bootable\bootloader\lk\target\msm8953\oem_panel.c 1-2 通过IC的ID区分 这种方法仅能区分不同IC的LCD模组。 1-3 通过LCD_ID和IC ID的结合区分 如下图P6600硬件原理图,通过 LCD_ID,并配置I2C获取IC的ID来区分不同屏幕。 Bootable\bootloader\lk\target\msm8953\oem_panel.c 2、LCD初始化过程 Bootable\bootloader\lk\target\msm8953\oem_panel.c 3、读取LK屏的ID传输到kernel 3-1 LK把相关参数报存到pbuf Bootable\bootloader\lk\dev\gcdb\display\gcdb_display_param.c 3-2 kernel获取LK保存的pbuf \kernel\init\main.c 3-3 解析出所用的LCD并初始化 \kernel\drivers\video\msm\mdss\mdss_dsi.c Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《[lcm] Qualcomm平台兼容多显示屏lcd的方法&并从lk传输到kernel过程》: http://blog.csdn.net/u014134180/article/details/78166978 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
0lk 启动总体流程 1lk启动流程代码 lk arch arm crt0S lk kernel mainc lk app appc 更多相关文章: 《高通Qualcomm平台lk(light kernel)启动流程1——aboot_init()之前》: http://blog.csdn.net/u014134180/article/details/78133916 《高通Qualcomm平台lk(light kernel)启动流程2——aboot_init()》: http://blog.csdn.net/u014134180/article/details/78132580 《高通Qualcomm平台lk(light kernel)启动流程3——到高通lcm屏点亮》: http://blog.csdn.net/u014134180/article/details/78177040 《[lcm] Qualcomm Android Display Subsystem 架构》 http://blog.csdn.net/u014134180/article/details/78129502 《[lcm] Qualcomm平台的显示屏lcd驱动移植步骤》: http://blog.csdn.net/u014134180/article/details/78129499 《[lcm] Qualcomm平台兼容多显示屏lcd的方法&并从lk传输到kernel过程》: http://blog.csdn.net/u014134180/article/details/78166978 《[lcm] Qualcomm平台显示屏lcd添加I2C读取功能》: http://blog.csdn.net/u014134180/article/details/78176160 0、lk 启动总体流程 1、lk启动流程代码 lk/ arch/ arm/ crt0.S /* * Copyright (c) 2008 Travis Geiselbrecht * * Copyright (c) 2014, The Linux Foundation. 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. */ #define DSB .byte 0x4f, 0xf0, 0x7f, 0xf5 #define ISB .byte 0x6f, 0xf0, 0x7f, 0xf5 .section ".text.boot" .globl _start _start: b reset b arm_undefined b arm_syscall b arm_prefetch_abort b arm_data_abort b arm_reserved b arm_irq b arm_fiq reset: #ifdef ENABLE_TRUSTZONE /*Add reference to TZ symbol so linker includes it in final image */ ldr r7, =_binary_tzbsp_tzbsp_bin_start #endif /* do some cpu setup */ #if ARM_WITH_CP15 /* Read SCTLR */ mrc p15, 0, r0, c1, c0, 0 /* XXX this is currently for arm926, revist with armv6 cores */ /* new thumb behavior, low exception vectors, i/d cache disable, mmu disabled */ bic r0, r0, #(1<<15| 1<<13 | 1<<12) bic r0, r0, #(1<<2 | 1<<0) /* disable alignment faults */ bic r0, r0, #(1<<1) /* Enable CP15 barriers by default */ #ifdef ARM_CORE_V8 orr r0, r0, #(1<<5) #endif /* Write SCTLR */ mcr p15, 0, r0, c1, c0, 0 #ifdef ENABLE_TRUSTZONE /*nkazi: not needed ? Setting VBAR to location of new vector table : 0x80000 */ ldr r0, =0x00080000 mcr p15, 0, r0, c12, c0, 0 #endif #endif #if WITH_CPU_EARLY_INIT /* call platform/arch/etc specific init code */ #ifndef ENABLE_TRUSTZONE /* Not needed when TrustZone is the first bootloader that runs.*/ bl __cpu_early_init #endif /* declare return address as global to avoid using stack */ .globl _cpu_early_init_complete _cpu_early_init_complete: #endif #if (!ENABLE_NANDWRITE) #if WITH_CPU_WARM_BOOT ldr r0, warm_boot_tag cmp r0, #1 /* if set, warm boot */ ldreq pc, =BASE_ADDR mov r0, #1 str r0, warm_boot_tag #endif #endif /* see if we need to relocate */ mov r0, pc sub r0, r0, #(.Laddr - _start) .Laddr: ldr r1, =_start cmp r0, r1 beq .Lstack_setup /* we need to relocate ourselves to the proper spot */ ldr r2, =__data_end .Lrelocate_loop: ldr r3, [r0], #4 str r3, [r1], #4 cmp r1, r2 bne .Lrelocate_loop /* we're relocated, jump to the right address */ ldr r0, =.Lstack_setup bx r0 .ltorg #if WITH_CPU_WARM_BOOT warm_boot_tag: .word 0 #endif .Lstack_setup: /* set up the stack for irq, fiq, abort, undefined, system/user, and lastly supervisor mode */ mrs r0, cpsr bic r0, r0, #0x1f ldr r2, =abort_stack_top orr r1, r0, #0x12 // irq msr cpsr_c, r1 ldr r13, =irq_save_spot /* save a pointer to a temporary dumping spot used during irq delivery */ orr r1, r0, #0x11 // fiq msr cpsr_c, r1 mov sp, r2 orr r1, r0, #0x17 // abort msr cpsr_c, r1 mov sp, r2 orr r1, r0, #0x1b // undefined msr cpsr_c, r1 mov sp, r2 orr r1, r0, #0x1f // system msr cpsr_c, r1 mov sp, r2 orr r1, r0, #0x13 // supervisor msr cpsr_c, r1 mov sp, r2 /* copy the initialized data segment out of rom if necessary */ ldr r0, =__data_start_rom ldr r1, =__data_start ldr r2, =__data_end cmp r0, r1 beq .L__do_bss .L__copy_loop: cmp r1, r2 ldrlt r3, [r0], #4 strlt r3, [r1], #4 blt .L__copy_loop .L__do_bss: /* clear out the bss */ ldr r0, =__bss_start ldr r1, =_end mov r2, #0 .L__bss_loop: cmp r0, r1 strlt r2, [r0], #4 blt .L__bss_loop #ifdef ARM_CPU_CORTEX_A8 DSB ISB #endif bl kmain b . .ltorg .bss .align 2 /* the abort stack is for unrecoverable errors. * also note the initial working stack is set to here. * when the threading system starts up it'll switch to a new * dynamically allocated stack, so we don't need it for very long */ abort_stack: .skip 1024 abort_stack_top: lk/ kernel/ main.c /* * Copyright (c) 2008 Travis Geiselbrecht * * Copyright (c) 2009-2014, The Linux Foundation. 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 <compiler.h> #include <debug.h> #include <string.h> #include <app.h> #include <arch.h> #include <platform.h> #include <target.h> #include <lib/heap.h> #include <kernel/thread.h> #include <kernel/timer.h> #include <kernel/dpc.h> #include <boot_stats.h> extern void *__ctor_list; extern void *__ctor_end; extern int __bss_start; extern int _end; static int bootstrap2(void *arg); #if (ENABLE_NANDWRITE) void bootstrap_nandwrite(void); #endif static void call_constructors(void) { void **ctor; ctor = &__ctor_list; while(ctor != &__ctor_end) { void (*func)(void); func = (void (*)())*ctor; func(); ctor++; } } /* called from crt0.S */ void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE; void kmain(void) { thread_t *thr; // get us into some sort of thread context thread_init_early(); // early arch stuff arch_early_init(); // do any super early platform initialization platform_early_init(); // do any super early target initialization target_early_init(); dprintf(INFO, "welcome to lk\n\n"); bs_set_timestamp(BS_BL_START); // deal with any static constructors dprintf(SPEW, "calling constructors\n"); call_constructors(); // bring up the kernel heap dprintf(SPEW, "initializing heap\n"); heap_init(); __stack_chk_guard_setup(); // initialize the threading system dprintf(SPEW, "initializing threads\n"); thread_init(); // initialize the dpc system dprintf(SPEW, "initializing dpc\n"); dpc_init(); // initialize kernel timers dprintf(SPEW, "initializing timers\n"); timer_init(); #if (!ENABLE_NANDWRITE) // create a thread to complete system initialization dprintf(SPEW, "creating bootstrap completion thread\n"); thr = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); if (!thr) { panic("failed to create thread bootstrap2\n"); } thread_resume(thr); // enable interrupts exit_critical_section(); // become the idle thread thread_become_idle(); #else bootstrap_nandwrite(); #endif } int main(void); static int bootstrap2(void *arg) { dprintf(SPEW, "top of bootstrap2()\n"); arch_init(); // XXX put this somewhere else #if WITH_LIB_BIO bio_init(); #endif #if WITH_LIB_FS fs_init(); #endif // initialize the rest of the platform dprintf(SPEW, "initializing platform\n"); platform_init(); // initialize the target dprintf(SPEW, "initializing target\n"); target_init(); dprintf(SPEW, "calling apps_init()\n"); apps_init(); return 0; } #if (ENABLE_NANDWRITE) void bootstrap_nandwrite(void) { dprintf(SPEW, "top of bootstrap2()\n"); arch_init(); // initialize the rest of the platform dprintf(SPEW, "initializing platform\n"); platform_init(); // initialize the target dprintf(SPEW, "initializing target\n"); target_init(); dprintf(SPEW, "calling nandwrite_init()\n"); nandwrite_init(); return 0; } #endif lk/ app/ app.c /* * Copyright (c) 2009 Travis Geiselbrecht * * 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 <debug.h> #include <app.h> #include <kernel/thread.h> extern const struct app_descriptor __apps_start; extern const struct app_descriptor __apps_end; static void start_app(const struct app_descriptor *app); /* one time setup */ void apps_init(void) { const struct app_descriptor *app; /* call all the init routines */ for (app = &__apps_start; app != &__apps_end; app++) { if (app->init) app->init(app); } /* start any that want to start on boot */ for (app = &__apps_start; app != &__apps_end; app++) { if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) { start_app(app); } } } static int app_thread_entry(void *arg) { const struct app_descriptor *app = (const struct app_descriptor *)arg; app->entry(app, NULL); return 0; } static void start_app(const struct app_descriptor *app) { thread_t *thr; printf("starting app %s\n", app->name); thr = thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); if(!thr) { return; } thread_resume(thr); } Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《高通Qualcomm平台lk(light kernel)启动流程1——aboot_init()之前》: http://blog.csdn.net/u014134180/article/details/78133916 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
下面在device目录过滤一下项目用到的”LK”的说明,发现在./msm8937_32/BoardConfig.mk和 ./msm8937_64/BoardConfig.mk都有配置信息: BOOTLOADER_PLATFORM := msm8952# use 8952 LK configuration 这说明Android这个用msm8937芯片的项目在LK的BOOTLOADER_PLATFORM用的是msm8952,所以以后在LK目录配置这个项目的信息都在msm8952相关的目录就可以了。 wuchengbing@ubuntu:~/gaotong/L2800/arm11/device/qcom$ grep LK -rw ./msm8937_* grep: ./msm8937_32/.git/shallow: No such file or directory Binary file ./msm8937_32/.git/objects/pack/pack-25986f956561d553d3649c555855208bf605d4f7.pack matches ./msm8937_32/BoardConfig.mk:BOOTLOADER_PLATFORM := msm8952# use 8952 LK configuration grep: ./msm8937_64/.git/shallow: No such file or directory Binary file ./msm8937_64/.git/objects/pack/pack-f3f84f664f70216af8bcf17228120672210069ef.pack matches ./msm8937_64/BoardConfig.mk:BOOTLOADER_PLATFORM := msm8952 # use msm8937 LK configuration wuchengbing@ubuntu:~/gaotong/L2800/arm11/device/qcom$ ./msm8937_32/BoardConfig.mk:BOOTLOADER_PLATFORM := msm8952# use 8952 LK configuration Wu_Being 博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《lk部分没有msm8937相关目录原因(指向msm8952)》 http://blog.csdn.net/u014134180/article/details/78132660 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
…/lk/project/msm8953.mk ifeq ($(TARGET_BUILD_VARIANT),user) DEBUG := 0 else DEBUG := 1 ENABLE_FBCON_DISPLAY_MSG := 1 endif ifeq ($(ENABLE_FBCON_DISPLAY_MSG),1) DEFINES += FBCON_DISPLAY_MSG=1 endif …/lk/app/aboot/aboot.c boot_init() dprintf(INFO, "** [wuchengbing] FBCON_DISPLAY_MSG:%d **\n", FBCON_DISPLAY_MSG); #if FBCON_DISPLAY_MSG dprintf(INFO, "** [wuchengbing] display_fastboot_menu(); **before\n"); display_fastboot_menu();// #endif wuchengbing@ubuntu:~/gaotong/P3590/arm11/zprojects$ grep TARGET_BUILD_VARIANT -rwn . ./lxf_p3590_b01/replace_files/device/qcom/msm8953_32/msm8953_32.mk:144: ifeq ($(TARGET_BUILD_VARIANT),user) ./lxf_p3590_b01/replace_files/build/core/main.mk:306:$(info Set TARGET_BUILD_VARIANT in buildspec.mk, or use lunch or) ./lxf_p3590_b01/replace_files/build/core/main.mk:313:ifneq ($(filter-out $(INTERNAL_VALID_VARIANTS),$(TARGET_BUILD_VARIANT)),) ./lxf_p3590_b01/replace_files/build/core/main.mk:316:$(info Invalid variant: $(TARGET_BUILD_VARIANT)) ./lxf_p3590_b01/replace_files/build/core/main.mk:388:user_variant := $(filter user userdebug,$(TARGET_BUILD_VARIANT)) ./lxf_p3590_b01/replace_files/build/core/main.mk:434:ifeq ($(TARGET_BUILD_VARIANT),eng) ./lxf_p3590_b01/replace_files/build/core/main.mk:1091:ifneq ($(filter eng userdebug,$(TARGET_BUILD_VARIANT)),) ./lxf_p3590_b01/env_lxf_p3590_b01.ini:11:TARGET_BUILD_VARIANT=userdebug zproject/lxf_p3590_b01/LCTPreConfig_lxf_p3590_b01.mk [lxf_p3590_b01] #LCT add begin version_no=26 ext_version_no=1.7 RF_verno=01 TARGET_SIMULATOR=false TARGET_PRODUCT=msm8953_64 TARGET_BUILD_TYPE=release TARGET_BUILD_VARIANT=userdebug Wu_Being 博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《Android eng版本开机有fastboot界面(lk代码分析)》 http://blog.csdn.net/u014134180/article/details/78132639 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
0lk 启动总体流程 1lk启动流程代码 lk app aboot abootc 更多相关文章: 《高通Qualcomm平台lk(light kernel)启动流程1——aboot_init()之前》: http://blog.csdn.net/u014134180/article/details/78133916 《高通Qualcomm平台lk(light kernel)启动流程2——aboot_init()》: http://blog.csdn.net/u014134180/article/details/78132580 《高通Qualcomm平台lk(light kernel)启动流程3——到高通lcm屏点亮》: http://blog.csdn.net/u014134180/article/details/78177040 《[lcm] Qualcomm Android Display Subsystem 架构》 http://blog.csdn.net/u014134180/article/details/78129502 《[lcm] Qualcomm平台的显示屏lcd驱动移植步骤》: http://blog.csdn.net/u014134180/article/details/78129499 《[lcm] Qualcomm平台兼容多显示屏lcd的方法&并从lk传输到kernel过程》: http://blog.csdn.net/u014134180/article/details/78166978 《[lcm] Qualcomm平台显示屏lcd添加I2C读取功能》: http://blog.csdn.net/u014134180/article/details/78176160 0、lk 启动总体流程 1、lk启动流程代码 lk/ app/ aboot/ aboot.c 下面是aboot.c的部分代码,核心代码在的aboot_init()函数开始:void aboot_init(const struct app_descriptor *app) /* * Copyright (c) 2009, Google Inc. * All rights reserved. * * Copyright (c) 2009-2016, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of The Linux Foundation nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include <app.h> #include <debug.h> #include <arch/arm.h> #include <string.h> #include <stdlib.h> #include <limits.h> #include <kernel/thread.h> #include <arch/ops.h> #include <dev/flash.h> #include <dev/flash-ubi.h> #include <lib/ptable.h> #include <dev/keys.h> #include <dev/fbcon.h> #include <baseband.h> #include <target.h> #include <mmc.h> #include <partition_parser.h> #include <platform.h> #include <crypto_hash.h> #include <malloc.h> #include <boot_stats.h> #include <sha.h> #include <platform/iomap.h> #include <boot_device.h> #include <boot_verifier.h> #include <image_verify.h> #include <decompress.h> #include <platform/timer.h> #include <sys/types.h> #if USE_RPMB_FOR_DEVINFO #include <rpmb.h> #endif #if ENABLE_WBC #include <pm_app_smbchg.h> #endif #if DEVICE_TREE #include <libfdt.h> #include <dev_tree.h> #endif #if WDOG_SUPPORT #include <wdog.h> #endif #include <reboot.h> #include "image_verify.h" #include "recovery.h" #include "bootimg.h" #include "fastboot.h" #include "sparse_format.h" #include "meta_format.h" #include "mmc.h" #include "devinfo.h" #include "board.h" #include "scm.h" #include "mdtp.h" #include "secapp_loader.h" #include <menu_keys_detect.h> #include <display_menu.h> #include "fastboot_test.h" #ifdef CONFIG_LK_CUSTOM_P3588 #include <smb1360.h> #endif #include <lct/lct_config.h> extern bool target_use_signed_kernel(void); extern void platform_uninit(void); extern void target_uninit(void); extern int get_target_boot_params(const char *cmdline, const char *part, char **buf); void *info_buf; void write_device_info_mmc(device_info *dev); void write_device_info_flash(device_info *dev); static int aboot_save_boot_hash_mmc(uint32_t image_addr, uint32_t image_size); static int aboot_frp_unlock(char *pname, void *data, unsigned sz); /* fastboot command function pointer */ typedef void (*fastboot_cmd_fn) (const char *, void *, unsigned); struct fastboot_cmd_desc { char * name; fastboot_cmd_fn cb; }; #define EXPAND(NAME) #NAME #define TARGET(NAME) EXPAND(NAME) #define DISPLAY_PANEL_HDMI "hdmi" #ifdef MEMBASE #define EMMC_BOOT_IMG_HEADER_ADDR (0xFF000+(MEMBASE)) #else #define EMMC_BOOT_IMG_HEADER_ADDR 0xFF000 #endif #ifndef MEMSIZE #define MEMSIZE 1024*1024 #endif #define MAX_TAGS_SIZE 1024 /* make 4096 as default size to ensure EFS,EXT4's erasing */ #define DEFAULT_ERASE_SIZE 4096 #define MAX_PANEL_BUF_SIZE 196 #define FOOTER_SIZE 16384 #define DISPLAY_DEFAULT_PREFIX "mdss_mdp" #define BOOT_DEV_MAX_LEN 64 #define IS_ARM64(ptr) (ptr->magic_64 == KERNEL64_HDR_MAGIC) ? true : false #define ADD_OF(a, b) (UINT_MAX - b > a) ? (a + b) : UINT_MAX //Size of the header that is used in case the boot image has //a uncompressed kernel + appended dtb #define PATCHED_KERNEL_HEADER_SIZE 20 //String used to determine if the boot image has //a uncompressed kernel + appended dtb #define PATCHED_KERNEL_MAGIC "UNCOMPRESSED_IMG" #if USE_BOOTDEV_CMDLINE static const char *emmc_cmdline = " androidboot.bootdevice="; #else static const char *emmc_cmdline = " androidboot.emmc=true"; #endif static const char *usb_sn_cmdline = " androidboot.serialno="; #ifdef CONFIG_LCT_CUSTOM_LX_COMMON static const char *lenovo_sn2_cmdline = " androidboot.lenovosn2="; #endif static const char *androidboot_mode = " androidboot.mode="; static const char *alarmboot_cmdline = " androidboot.alarmboot=true"; static const char *loglevel = " quiet"; static const char *battchg_pause = " androidboot.mode=charger"; static const char *androidboot = " androidboot."; //static const char *country_code = "countrycode="; static const char *auth_kernel = " androidboot.authorized_kernel=true"; static const char *secondary_gpt_enable = " gpt"; static const char *mdtp_activated_flag = " mdtp"; static const char *baseband_apq = " androidboot.baseband=apq"; static const char *baseband_msm = " androidboot.baseband=msm"; static const char *baseband_csfb = " androidboot.baseband=csfb"; static const char *baseband_svlte2a = " androidboot.baseband=svlte2a"; static const char *baseband_mdm = " androidboot.baseband=mdm"; static const char *baseband_mdm2 = " androidboot.baseband=mdm2"; static const char *baseband_sglte = " androidboot.baseband=sglte"; static const char *baseband_dsda = " androidboot.baseband=dsda"; static const char *baseband_dsda2 = " androidboot.baseband=dsda2"; static const char *baseband_sglte2 = " androidboot.baseband=sglte2"; static const char *warmboot_cmdline = " qpnp-power-on.warm_boot=1"; static const char *baseband_apq_nowgr = " androidboot.baseband=baseband_apq_nowgr"; #if VERIFIED_BOOT #if !VBOOT_MOTA static const char *verity_mode = " androidboot.veritymode="; static const char *verified_state= " androidboot.verifiedbootstate="; static const char *keymaster_v1= " androidboot.keymaster=1"; //indexed based on enum values, green is 0 by default struct verified_boot_verity_mode vbvm[] = { #if ENABLE_VB_ATTEST {false, "eio"}, #else {false, "logging"}, #endif {true, "enforcing"}, }; struct verified_boot_state_name vbsn[] = { {GREEN, "green"}, {ORANGE, "orange"}, {YELLOW,"yellow"}, {RED,"red" }, }; #endif #endif /*As per spec delay wait time before shutdown in Red state*/ #define DELAY_WAIT 30000 static unsigned page_size = 0; static unsigned page_mask = 0; static unsigned mmc_blocksize = 0; static unsigned mmc_blocksize_mask = 0; static char ffbm_mode_string[FFBM_MODE_BUF_SIZE]; static char area_code_string[AREA_CODE_BUF_SIZE]; static bool boot_into_ffbm; static bool get_area_code; static char *target_boot_params = NULL; static bool boot_reason_alarm; static bool devinfo_present = true; bool boot_into_fastboot = false; static uint32_t dt_size = 0; /* Assuming unauthorized kernel image by default */ static int auth_kernel_img = 0; #if VBOOT_MOTA static device_info device = {DEVICE_MAGIC, 0, 0, 0, 0, {0}, {0},{0}}; #else static device_info device = {DEVICE_MAGIC, 0, 0, 0, 0, {0}, {0},{0}, 1}; #endif static bool is_allow_unlock = 0; static char frp_ptns[2][8] = {"config","frp"}; static const char *critical_flash_allowed_ptn[] = { "aboot", "rpm", "tz", "sbl", "sdi", "sbl1", "xbl", "hyp", "pmic", "bootloader", "devinfo", "partition"}; struct atag_ptbl_entry { char name[16]; unsigned offset; unsigned size; unsigned flags; }; /* * Partition info, required to be published * for fastboot */ struct getvar_partition_info { const char part_name[MAX_GPT_NAME_SIZE]; /* Partition name */ char getvar_size[MAX_GET_VAR_NAME_SIZE]; /* fastboot get var name for size */ char getvar_type[MAX_GET_VAR_NAME_SIZE]; /* fastboot get var name for type */ char size_response[MAX_RSP_SIZE]; /* fastboot response for size */ char type_response[MAX_RSP_SIZE]; /* fastboot response for type */ }; /* * Right now, we are publishing the info for only * three partitions */ struct getvar_partition_info part_info[] = { { "system" , "partition-size:", "partition-type:", "", "ext4" }, { "userdata", "partition-size:", "partition-type:", "", "ext4" }, { "cache" , "partition-size:", "partition-type:", "", "ext4" }, }; char max_download_size[MAX_RSP_SIZE]; char charger_screen_enabled[MAX_RSP_SIZE]; char sn_buf[13]; char lenovo_sn2_buf[32]; char display_panel_buf[MAX_PANEL_BUF_SIZE]; char panel_display_mode[MAX_RSP_SIZE]; #if CHECK_BAT_VOLTAGE char battery_voltage[MAX_RSP_SIZE]; char battery_soc_ok [MAX_RSP_SIZE]; #endif char get_variant[MAX_RSP_SIZE]; extern int emmc_recovery_init(void); #if NO_KEYPAD_DRIVER extern int fastboot_trigger(void); #endif 。。。 。。。 void aboot_init(const struct app_descriptor *app) { dprintf(INFO, "** [wuchengbing] %s %d %s **.\n", __FILE__, __LINE__, __func__); unsigned reboot_mode = 0; dprintf(INFO, "** [wuchengbing] %d: reboot_mode:%#x **\n", __LINE__, reboot_mode); ///reboot_mode dprintf(INFO, "** [wuchengbing] %d: boot_into_fastboot:%#x **\n", __LINE__, boot_into_fastboot); ///reboot_mode /* Initialise wdog to catch early lk crashes */ #if WDOG_SUPPORT msm_wdog_init(); #endif /* Setup page size information for nv storage */ if (target_is_emmc_boot()) { dprintf(INFO, "** [wuchengbing] %d: if(target_is_emmc_boot()): %d**.\n", __LINE__, target_is_emmc_boot()); page_size = mmc_page_size(); page_mask = page_size - 1; mmc_blocksize = mmc_get_device_blocksize(); mmc_blocksize_mask = mmc_blocksize - 1; } else { dprintf(INFO, "** [wuchengbing] %d: else:%d**.\n", __LINE__, target_is_emmc_boot()); page_size = flash_page_size(); page_mask = page_size - 1; } ASSERT((MEMBASE + MEMSIZE) > MEMBASE); dprintf(INFO, "** [wuchengbing] %d: reboot_mode:%#x **\n", __LINE__, reboot_mode); ///reboot_mode dprintf(INFO, "** [wuchengbing] %d: boot_into_fastboot:%#x **\n", __LINE__, boot_into_fastboot); ///boot_into_fastboot #ifdef CONFIG_LK_CUSTOM_P3588 smb1360_init(); #endif read_device_info(&device); read_allow_oem_unlock(&device); dprintf(INFO, "** [wuchengbing] %d: reboot_mode:%#x **\n", __LINE__, reboot_mode); ///reboot_mode dprintf(INFO, "** [wuchengbing] %d: boot_into_fastboot:%#x **\n", __LINE__, boot_into_fastboot); ///boot_into_fastboot target_serialno((unsigned char *) sn_buf); get_sn(sn_buf); dprintf(SPEW,"serial number: %s\n",sn_buf); #ifdef CONFIG_LCT_CUSTOM_LX_COMMON get_lenovo_sn2(); dprintf(INFO,"lenovo serial number: %s\n",lenovo_sn2_buf); #endif memset(display_panel_buf, '\0', MAX_PANEL_BUF_SIZE); /* * Check power off reason if user force reset, * if yes phone will do normal boot. */ if (is_user_force_reset()) { dprintf(INFO, "** [wuchengbing] is_user_force_reset():%d**.\n", is_user_force_reset()); dprintf(INFO, "** [wuchengbing] %d: reboot_mode:%#x **\n", __LINE__, reboot_mode); ///reboot_mode dprintf(INFO, "** [wuchengbing] %d: boot_into_fastboot:%#x **\n", __LINE__, boot_into_fastboot);///boot_into_fastboot goto normal_boot; } /* Check if we should do something other than booting up */ dprintf(INFO, "** [wuchengbing] %d: (KEY_VOLUMEUP):%d , (KEY_VOLUMEDOWN):%d **.\n", __LINE__, (KEY_VOLUMEUP), (KEY_VOLUMEDOWN)); dprintf(INFO, "** [wuchengbing] %d: keys_get_state(KEY_VOLUMEUP):%d && keys_get_state(KEY_VOLUMEDOWN):%d **.\n", __LINE__, keys_get_state(KEY_VOLUMEUP), keys_get_state(KEY_VOLUMEDOWN)); if (keys_get_state(KEY_VOLUMEUP) && keys_get_state(KEY_VOLUMEDOWN)) ///boot_into_ffbm = true; { #if 0 dprintf(ALWAYS,"dload mode key sequence detected\n"); reboot_device(EMERGENCY_DLOAD); dprintf(CRITICAL,"Failed to reboot into dload mode\n"); dprintf(INFO, "** [wuchengbing] boot_into_fastboot ;** if.\n"); boot_into_fastboot = true; #else dprintf(INFO, "** [wuchengbing] boot_into_ffbm = true;** if.\n"); boot_into_ffbm = true; ///boot_into_ffbm = true; strcpy(ffbm_mode_string, "ffbm-00"); #endif dprintf(INFO, "** [wuchengbing] %d: reboot_mode:%#x **\n", __LINE__, reboot_mode); ///reboot_mode dprintf(INFO, "** [wuchengbing] %d: boot_into_fastboot:%#x **\n", __LINE__, boot_into_fastboot);///boot_into_fastboot } else{ dprintf(INFO, "**[wuchengbing] %d: boot_into_ffbm = false;** else.\n", __LINE__); boot_into_ffbm = false; // strcpy(ffbm_mode_string, "nomal"); } dprintf(INFO, "** [wuchengbing] %d: (boot_into_fastboot):%d && (boot_into_ffbm):%d **.\n", __LINE__, (boot_into_fastboot), (boot_into_ffbm)); dprintf(INFO, "** [wuchengbing] %d: (!boot_into_fastboot):%d && (!boot_into_ffbm):%d **.\n", __LINE__, (!boot_into_fastboot), (!boot_into_ffbm)); if (!boot_into_fastboot&&!boot_into_ffbm ) { dprintf(INFO, "** [wuchengbing] %d: (KEY_HOME):%d , (KEY_VOLUMEUP):%d **.\n", __LINE__, (KEY_HOME), (KEY_VOLUMEUP)); dprintf(INFO, "** [wuchengbing] %d: keys_get_state(KEY_HOME):%d || keys_get_state(KEY_VOLUMEUP):%d **.\n", __LINE__, keys_get_state(KEY_HOME), keys_get_state(KEY_VOLUMEUP)); if (keys_get_state(KEY_HOME) || keys_get_state(KEY_VOLUMEUP)) ///boot_into_recovery = 1; { dprintf(INFO, "** [wuchengbing] if(usb_exist):%d **.\n", (usb_exist)); if(usb_exist) ///lc mike_zhu 2016121f13 ///boot_into_recovery = 1; { dprintf(INFO, "** [wuchengbing] (EMERGENCY_DLOAD):%d **.if\n", (EMERGENCY_DLOAD)); reboot_device(EMERGENCY_DLOAD); } else { dprintf(INFO, "** [wuchengbing] boot_into_recovery = 1; **.else\n"); boot_into_recovery = 1; } } dprintf(INFO, "** [wuchengbing] %d: boot_into_recovery:%d , (KEY_BACK):%d , (KEY_VOLUMEDOWN):%d **.\n", __LINE__, boot_into_recovery, (KEY_HOME), (KEY_VOLUMEDOWN)); dprintf(INFO, "** [wuchengbing] %d: if( !boot_into_recovery==%d || ( keys_get_state(KEY_BACK)==%d || keys_get_state(KEY_VOLUMEDOWN)==%d) ) **.\n", __LINE__, !boot_into_recovery, keys_get_state(KEY_BACK), keys_get_state(KEY_VOLUMEDOWN)); if (!boot_into_recovery && (keys_get_state(KEY_BACK) || keys_get_state(KEY_VOLUMEDOWNlp)))///boot_into_fastboot = true; { dprintf(INFO, "** [wuchengbing] boot_into_fastboot = true; **.if\n"); boot_into_fastboot = true; } } #if NO_KEYPAD_DRIVER dprintf(INFO, "** [wuchengbing] fastboot_trigger():%d **\n", fastboot_trigger()); if (fastboot_trigger()) { dprintf(INFO, "** [wuchengbing] boot_into_fastboot = true; **.if\n"); ///boot_into_fastboot = true; boot_into_fastboot = true; } #endif //dprintf(INFO, "** [wuchengbing] USE_PON_REBOOT_REG:%d **\n", USE_PON_REBOOT_REG); #if USE_PON_REBOOT_REG reboot_mode = check_hard_reboot_mode(); #else reboot_mode = check_reboot_mode(); dprintf(INFO, "** [wuchengbing] %d:check_reboot_mode() reboot_mode:%#x ** \n", __LINE__, reboot_mode); ///reboot_mode dprintf(INFO, "** [wuchengbing] %d:check_reboot_mode() boot_into_fastboot:%#x **\n", __LINE__, boot_into_fastboot); ///boot_into_fastboot #endif dprintf(INFO, "** [wuchengbing] %d: reboot_mode:%#x **\n", __LINE__, reboot_mode); ///reboot_mode dprintf(INFO, "** [wuchengbing] RECOVERY_MODE:%#x **\n", RECOVERY_MODE); dprintf(INFO, "** [wuchengbing] FASTBOOT_MODE:%#x **\n", FASTBOOT_MODE); ///FASTBOOT_MODE dprintf(INFO, "** [wuchengbing] ALARM_BOOT:%#x **\n", ALARM_BOOT); dprintf(INFO, "** [wuchengbing] DM_VERITY_ENFORCING:%#x **\n", DM_VERITY_ENFORCING); dprintf(INFO, "** [wuchengbing] DM_VERITY_EIO:%#x **\n", DM_VERITY_EIO); dprintf(INFO, "** [wuchengbing] ALARM_BOOT:%#x **\n", ALARM_BOOT); //dprintf(INFO, "** [wuchengbing] DM_VERITY_LOGGING:%#x **\n", DM_VERITY_LOGGING); dprintf(INFO, "** [wuchengbing] DM_VERITY_KEYSCLEAR:%#x **\n\n", DM_VERITY_KEYSCLEAR); dprintf(INFO, "** [wuchengbing] VERIFIED_BOOT:%d ...**\n\n", VERIFIED_BOOT); if (reboot_mode == RECOVERY_MODE) { dprintf(INFO, "** [wuchengbing] RECOVERY_MODE:%d **\n", RECOVERY_MODE); boot_into_recovery = 1; } else if(reboot_mode == FASTBOOT_MODE) { dprintf(INFO, "** [wuchengbing] FASTBOOT_MODE:%d **\n", FASTBOOT_MODE); boot_into_fastboot = true; } else if(reboot_mode == ALARM_BOOT) { dprintf(INFO, "** [wuchengbing] ALARM_BOOT:%d **\n", ALARM_BOOT); boot_reason_alarm = true; } #if VERIFIED_BOOT //1 //dprintf(INFO, "** [wuchengbing] !VBOOT_MOTA:%d **\n", !VBOOT_MOTA); #if !VBOOT_MOTA else if (reboot_mode == DM_VERITY_ENFORCING) { dprintf(INFO, "** [wuchengbing] DM_VERITY_ENFORCING:%d **\n", DM_VERITY_ENFORCING); device.verity_mode = 1; write_device_info(&device); } //dprintf(INFO, "** [wuchengbing] ENABLE_VB_ATTEST:%d **\n", ENABLE_VB_ATTEST); #if ENABLE_VB_ATTEST else if (reboot_mode == DM_VERITY_EIO) #else else if (reboot_mode == DM_VERITY_LOGGING) #endif { dprintf(INFO, "** [wuchengbing] DM_VERITY_EIO:%d **\n", DM_VERITY_EIO); //dprintf(INFO, "** [wuchengbing] DM_VERITY_LOGGING:%d **\n", DM_VERITY_LOGGING); device.verity_mode = 0; write_device_info(&device); } else if (reboot_mode == DM_VERITY_KEYSCLEAR) { dprintf(INFO, "** [wuchengbing] DM_VERITY_KEYSCLEAR:%d **\n", DM_VERITY_KEYSCLEAR); if(send_delete_keys_to_tz()) ASSERT(0); } #endif #endif dprintf(INFO, "** [wuchengbing] %d: normal_boot:** before\n", __LINE__); normal_boot: dprintf(INFO, "** [wuchengbing] %d: normal_boot:** after.\n", __LINE__); /* Display splash screen if enabled */ dprintf(INFO, "** [wuchengbing] DISPLAY_SPLASH_SCREEN:%d **\n", DISPLAY_SPLASH_SCREEN); #if DISPLAY_SPLASH_SCREEN // //dprintf(INFO, "** [wuchengbing] NO_ALARM_DISPLAY:%d **\n", NO_ALARM_DISPLAY); #if NO_ALARM_DISPLAY ///NO_ALARM_DISPLAY if (!check_alarm_boot()) { #endif dprintf(INFO, "Display Init: Start\n"); //dprintf(INFO, "** [wuchengbing] DISPLAY_HDMI_PRIMARY:%d **\n", DISPLAY_HDMI_PRIMARY); #if DISPLAY_HDMI_PRIMARY if (!strlen(device.display_panel)) strlcpy(device.display_panel, DISPLAY_PANEL_HDMI, sizeof(device.display_panel)); #endif //dprintf(INFO, "** [wuchengbing] ENABLE_WBC:%d **\n", ENABLE_WBC); #if ENABLE_WBC /* Wait if the display shutdown is in progress */ while(pm_app_display_shutdown_in_prgs()); if (!pm_appsbl_display_init_done()) target_display_init(device.display_panel); else display_image_on_screen(); #else target_display_init(device.display_panel); #endif dprintf(INFO, "Display Init: Done\n"); //dprintf(INFO, "** [wuchengbing] NO_ALARM_DISPLAY:%d **\n", NO_ALARM_DISPLAY); #if NO_ALARM_DISPLAY ///NO_ALARM_DISPLAY } #endif #endif //DISPLAY_SPLASH_SCREEN dprintf(INFO, "** [wuchengbing] if(!boot_into_fastboot == %d)**\n", !boot_into_fastboot); if (!boot_into_fastboot) { dprintf(INFO, "** [wuchengbing] if(target_is_emmc_boot = %d)**\n", target_is_emmc_boot()); if (target_is_emmc_boot()) { dprintf(INFO, "** [wuchengbing] %d: if(target_is_emmc_boot == %d)** if \n", __LINE__, target_is_emmc_boot()); dprintf(INFO, "** [wuchengbing] if(emmc_recovery_init == %d)**\n", emmc_recovery_init()); if(emmc_recovery_init()) { dprintf(ALWAYS,"error in emmc_recovery_init\n"); } dprintf(INFO, "** [wuchengbing] if(target_use_signed_kernel == %d)**\n", target_use_signed_kernel()); if(target_use_signed_kernel()) { dprintf(INFO, "** [wuchengbing] if((device.is_unlocked == %d) || (device.is_tampered == %d))**\n", (device.is_unlocked) , (device.is_tampered)); if((device.is_unlocked) || (device.is_tampered)) { //dprintf(INFO, "** [wuchengbing] TZ_TAMPER_FUSE:%d **\n", TZ_TAMPER_FUSE); #ifdef TZ_TAMPER_FUSE set_tamper_fuse_cmd(); #endif //dprintf(INFO, "** [wuchengbing] USE_PCOM_SECBOOT:%d **\n", USE_PCOM_SECBOOT); #if USE_PCOM_SECBOOT set_tamper_flag(device.is_tampered); #endif } } boot_linux_from_mmc();// } else { dprintf(INFO, "** [wuchengbing] %d: if(target_is_emmc_boot == %d)** else \n", __LINE__, target_is_emmc_boot()); recovery_init(); //dprintf(INFO, "** [wuchengbing] USE_PCOM_SECBOOT:%d **\n", USE_PCOM_SECBOOT); #if USE_PCOM_SECBOOT dprintf(INFO, "** [wuchengbing] if((device.is_unlocked = %d) || (device.is_tampered = %d))**\n", (device.is_unlocked) , (device.is_tampered)); if((device.is_unlocked) || (device.is_tampered)) { set_tamper_flag(device.is_tampered); } #endif boot_linux_from_flash(); } dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting " "to fastboot mode.\n"); } /* We are here means regular boot did not happen. Start fastboot. */ dprintf(INFO, "** [wuchengbing] aboot_fastboot_register_commands();**before\n"); /* register aboot specific fastboot commands */ aboot_fastboot_register_commands(); dprintf(INFO, "** [wuchengbing] Upartition_dump(); **before\n"); /* dump partition table for debug info */ partition_dump(); dprintf(INFO, "** [wuchengbing] fastboot_init(target_get_scratch_address(), target_get_max_flash_size()); **before\n"); /* initialize and start fastboot */ fastboot_init(target_get_scratch_address(), target_get_max_flash_size()); dprintf(INFO, "** [wuchengbing] FBCON_DISPLAY_MSG:%d **\n", FBCON_DISPLAY_MSG); #if FBCON_DISPLAY_MSG dprintf(INFO, "** [wuchengbing] display_fastboot_menu(); **before\n"); display_fastboot_menu(); #endif dprintf(INFO, "** [wuchengbing] %d: aboot() end **\n", __LINE__); } 。。。 。。。 APP_START(aboot) .init = aboot_init, APP_END Wu_Being 博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《高通Qualcomm平台lk(light kernel)启动流程2——aboot_init()》 http://blog.csdn.net/u014134180/article/details/78132580 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
[2017/8/16 14:47] 吴成兵: 这些都87工模测试的代码吗 [2017/8/16 15:00] 吴成兵: 单编工模代码是make system吗 [2017/8/16 15:23] 牛小燕: 单编是在 package/app/midtest, 下直接 mm 编出来的是在 system/app/midtest 下编出来push进去 [2017/8/16 15:24] 吴成兵:哦,push到哪个目录 [2017/8/16 15:25] 牛小燕: push到system/app/midtest/, push完reboot 注: 如果在单编出现说缺少某个包,则mmm单编缺少包的目录,在原来的目录再mm单编,直到mm编译成功并生成对应文件; push前记得要root和remount: C:\Users\wuchengbing> C:\Users\wuchengbing>adb root adbd is already running as root C:\Users\wuchengbing>adb remount remount succeeded C:\Users\wuchengbing>adb push F:\out_bin_w5910\system\framework\android.policy.jar system/framework 966 KB/s (144019 bytes in 0.145s) C:\Users\wuchengbing> Wu_Being 博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《单独编译工模&push替换烧写》 http://blog.csdn.net/u014134180/article/details/78129525 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
更多相关文章: 《高通Qualcomm平台lk(light kernel)启动流程1——aboot_init()之前》: http://blog.csdn.net/u014134180/article/details/78133916 《高通Qualcomm平台lk(light kernel)启动流程2——aboot_init()》: http://blog.csdn.net/u014134180/article/details/78132580 《高通Qualcomm平台lk(light kernel)启动流程3——到高通lcm屏点亮》: http://blog.csdn.net/u014134180/article/details/78177040 《[lcm] Qualcomm Android Display Subsystem 架构》 http://blog.csdn.net/u014134180/article/details/78129502 《[lcm] Qualcomm平台的显示屏lcd驱动移植步骤》: http://blog.csdn.net/u014134180/article/details/78129499 《[lcm] Qualcomm平台兼容多显示屏lcd的方法&并从lk传输到kernel过程》: http://blog.csdn.net/u014134180/article/details/78166978 《[lcm] Qualcomm平台显示屏lcd添加I2C读取功能》: http://blog.csdn.net/u014134180/article/details/78176160 Wu_Being 博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《[lcm] Qualcomm Android Display Subsystem 架构》 http://blog.csdn.net/u014134180/article/details/78129502 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
1lk部分 1-1 target_displayc 1-2 oem_panelc 1-3 panel_innont51021b_1200p_videoh 2Kernel 2-1 dsi-panel-boent51012_1200_videodtsi 2-2 msm8953-mdss-panelsdtsi 2-3 msm8953-mtpdtsi 更多相关文章: 《高通Qualcomm平台lk(light kernel)启动流程1——aboot_init()之前》: http://blog.csdn.net/u014134180/article/details/78133916 《高通Qualcomm平台lk(light kernel)启动流程2——aboot_init()》: http://blog.csdn.net/u014134180/article/details/78132580 《高通Qualcomm平台lk(light kernel)启动流程3——到高通lcm屏点亮》: http://blog.csdn.net/u014134180/article/details/78177040 《[lcm] Qualcomm Android Display Subsystem 架构》 http://blog.csdn.net/u014134180/article/details/78129502 《[lcm] Qualcomm平台的显示屏lcd驱动移植步骤》: http://blog.csdn.net/u014134180/article/details/78129499 《[lcm] Qualcomm平台兼容多显示屏lcd的方法&并从lk传输到kernel过程》: http://blog.csdn.net/u014134180/article/details/78166978 《[lcm] Qualcomm平台显示屏lcd添加I2C读取功能》: http://blog.csdn.net/u014134180/article/details/78176160 1、lk部分 Lk部分的移植主要就下面三个文件。 前提要在文件target_display.c打开配光功能。其中,.h头文件是LCM供应商给的文件,我们移植还要修改我们目标平台msm8953的oem_panel.c: 1-1 target_display.c 1-2 oem_panel.c 1、首先要引用LCM供应商给的面板数据集头文件,下面初始化数据要用到这些数据。 2、在LCM枚举变量中声明定义该面板id。 3、目标面板支持列表中加入该面板名字和id。 4、当屏幕面板点亮前,根据不用面板先延迟一定的时间数。 5、先要在oem_panel_select()的get_lcd_id()获取panel_id,然后后面根据这个panel_id进行初始面板。 6、下面就是根据面板ID对应初始化那个面板,面板数据就在供应商给的数据集头文件中(上面已说的) 7、第5步oem_panel_select()中的get_lcd_id()实现。 lcd_id0和lcd_id1分别接在gpio的12和13引脚里。 1-3 panel_innont51021b_1200p_video.h 2、Kernel 2-1 dsi-panel-boent51012_1200_video.dtsi 必须和lk通过cmdline传递给kernel一致 2-2 msm8953-mdss-panels.dtsi 上电部分 拉GPIO口: //kernel/drivers/video/msm/mdss/mdss_dsi_panel.c //kernel/drivers/video/msm/mdss/mdss_dsi.c 2-3 msm8953-mtp.dtsi Wu_Being 博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《[lcm] Qualcomm平台的显示屏lcd驱动移植步骤》:http://blog.csdn.net/u014134180/article/details/78129499 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
0Android JNI实例代码总体流程图 1C代码部分 2C代码部分 3Java代码部分 0、Android JNI实例代码总体流程图 1、C代码部分 2、C++代码部分 3、Java代码部分 Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《Android JNI的实例代码流程图》: http://blog.csdn.net/u014134180/article/details/78125723 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
1向节点读数据cat 例子1 例子2 2向节点写数据echo 例子 3添加节点方法 proc_create的使用例子 添加节点例子1 添加节点例子2 1向节点读数据cat 命令:cat /proc/节点名 例子1: C:\Users\wuchengbing>adb shell root@M1:/ # cat proc/tp_info cat proc/tp_info [Vendor]guangtai, [fw]0x01, [IC]HX8527 root@M1:/ # 例子2: root@M1:/sys/class/leds/lcd-backlight # cat /proc/devicesinfo name module vender IC Version info used LCM JD-45FS0005-V0 JUNDA ILI9806E (null)480*854 false ... ... 2向节点写数据echo 命令:echo 80 > brightness 例子: root@M1:/sys/class/leds/lcd-backlight # ls ls brightness device div duty frequency max_brightness power pwm_register subsystem trigger uevent root@M1:/sys/class/leds/lcd-backlight # echo 80 > brightness 3添加节点方法 proc_create(CTP_PROC_FILE, 0444, NULL,&gtp_info_proc_fops): 创建节点函数 CTP_PROC_FILE:节点名字 NULL: 基于/proc/目录下创建节点 gtp_info_proc_fops:节点文件结构体 copy_to_user():复制到用户空间函数 proc_create的使用例子 _gProcClassEntry = proc_mkdir(PROC_NODE_CLASS, NULL); _gProcMsTouchScreenMsg20xxEntry = proc_mkdir(PROC_NODE_MS_TOUCHSCREEN_MSG20XX, _gProcClassEntry); _gProcDeviceEntry = proc_mkdir(PROC_NODE_DEVICE, _gProcMsTouchScreenMsg20xxEntry); _gProcChipTypeEntry = proc_create(PROC_NODE_CHIP_TYPE, PROCFS_AUTHORITY, _gProcDeviceEntry, &_gProcChipType); if (NULL == _gProcChipTypeEntry) { DBG(&g_I2cClient->dev, "Failed to create procfs file node(%s)!\n", PROC_NODE_CHIP_TYPE); } else { DBG(&g_I2cClient->dev, "Create procfs file node(%s) OK!\n", PROC_NODE_CHIP_TYPE); } 添加节点例子1 #define LCT_ADD_TP_VERSION #if defined(LCT_ADD_TP_VERSION) #define CTP_PROC_FILE "tp_info" static struct proc_dir_entry *g_ctp_proc = NULL; static int gtp_info_read_proc(struct file *file, char *buffer, size_t count, loff_t *ppos) { char *page = NULL; char *ptr = NULL; char *manu_string=NULL; int len, err = -1; page = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!page) { kfree(page); return -ENOMEM; } if (private_ts->vendor_sensor_id == 34){ manu_string = "dijing"; }else if (private_ts->vendor_sensor_id == 18){ manu_string = "tongxingda"; }else{ manu_string = "Unknow"; } ptr = page; ptr += sprintf(ptr, "[Vendor]%s, [fw]0x%02x, [IC]HX8527\n", manu_string,private_ts->vendor_config_ver); len = ptr - page; if(*ppos >= len){ kfree(page); return 0; } err = copy_to_user(buffer,(char *)page,len); *ppos += len; if(err){ kfree(page); return err; } kfree(page); return len; }//gtp_info_read_proc static const struct file_operations gtp_info_proc_fops = { .write = NULL, # echo 80 > brightness .read = gtp_info_read_proc // # cat proc/tp_info }; #endif static int himax852xes_probe(struct i2c_client *client, const struct i2c_device_id *id) {... /* LCT_ADD_TP_VERSION */ //creat tp_info proc file system #if defined(LCT_ADD_TP_VERSION) g_ctp_proc = proc_create(CTP_PROC_FILE, 0444, NULL,&gtp_info_proc_fops); if (g_ctp_proc == NULL) { printk("create_proc_entry failed\n"); } #endif ... return 0; ... }//himax852xes_probe 添加节点例子2 #define CONFIG_SLT_DEVINFO_CTP #ifdef CONFIG_SLT_DEVINFO_CTP #include<linux/dev_info.h> struct devinfo_struct *s_DEVINFO_ctp = NULL; static char *temp_ver; static char *temp_ver_config; static void devinfo_ctp_regchar(char *module,char * vendor,char *version,char *config,char *used) { s_DEVINFO_ctp =(struct devinfo_struct*) kmalloc(sizeof(struct devinfo_struct), GFP_KERNEL); s_DEVINFO_ctp->device_type="CTP"; s_DEVINFO_ctp->device_module=module; s_DEVINFO_ctp->device_vendor=vendor; s_DEVINFO_ctp->device_ic="HX8527"; s_DEVINFO_ctp->device_info=config;//DEVINFO_NULL; s_DEVINFO_ctp->device_version=version; s_DEVINFO_ctp->device_used=used; devinfo_check_add_device(s_DEVINFO_ctp); //-> kernel/drivers/dev_info/dev_info.c:slt_devinfo_init(){proc_create("devicesinfo",...,&devinfo_stats_fops);} }//cat /proc/devicesinfo #endif static int himax852xes_probe(struct i2c_client *client, const struct i2c_device_id *id) {... /* CONFIG_SLT_DEVINFO_CTP */ #ifdef CONFIG_SLT_DEVINFO_CTP temp_ver = (char*)kmalloc(8,GFP_KERNEL); sprintf(temp_ver,"0x%04x",(private_ts->vendor_fw_ver_H << 8)|private_ts->vendor_fw_ver_L); temp_ver_config = (char*)kmalloc(8,GFP_KERNEL); sprintf(temp_ver_config,"0x%02x",private_ts->vendor_config_ver); switch(private_ts->vendor_sensor_id) { case 34: devinfo_ctp_regchar("dijing,", "dijing.", temp_ver, temp_ver_config,DEVINFO_USED); break; case 18: devinfo_ctp_regchar("tongxingda,", "tongxingda.", temp_ver, temp_ver_config,DEVINFO_USED); break; default: devinfo_ctp_regchar("unknown.1", "unknown.2", "unknown.3", "unknown.4",DEVINFO_USED); break; } #endif return 0; ... } kernel/drivers/dev_info/dev_info.c /********************************************************************************* * This functions is designed to check if declared already, and add new device if not yet; * Input: devinfo_struct * Output: 1 / 0 * Note: return 1 for there have a same device registed,0 for new device * *******************************************************************************/ int devinfo_check_add_device(struct devinfo_struct *dev) { int result = 0; unsigned long irqflags; struct devinfo_struct *dev_all; printk("[DEVINFO] devinfo_check!\n"); spin_lock_irqsave(&dev_lock, irqflags); if(list_empty(&active_devinfo_list) != 1) list_for_each_entry(dev_all, &active_devinfo_list, device_link) { printk("[DEVINFO] dev type:%s\n",dev->device_type); printk("[DEVINFO] dev list type:%s\n",dev_all->device_type); if((strcmp(dev_all->device_type,dev->device_type)==0) && (strcmp(dev_all->device_module,dev->device_module)==0) && (strcmp(dev_all->device_vendor,dev->device_vendor)==0) && (strcmp(dev_all->device_ic,dev->device_ic)==0) && (strcmp(dev_all->device_version,dev->device_version)==0) &&(strcmp(dev_all->device_info,dev->device_info)==0))// && shaohui mods here // It will be replaced if there is a used device found! Do not mention HOT plug device! 2013.01.31 // (strcmp(dev_all->device_used,dev->device_used)==0)) { if(strcmp(dev_all->device_used,dev->device_used)==0) { printk("[DEVINFO] find the same device\n"); }else if(strcmp(dev_all->device_used,DEVINFO_UNUSED)==0) { //we belive that we find a existed device! del the unexisted one! printk("[DEVINFO] find device,but unused state!\n"); list_del(&dev_all->device_link); list_add_tail(&dev->device_link, &active_devinfo_list); // list_replace(&dev_all->device_link, &active_devinfo_list); spin_unlock_irqrestore(&dev_lock, irqflags); return 0; }else{ //If a for-existed device is found lost,Do nothing~ printk("[DEVINFO] find device,but used state!\n"); } spin_unlock_irqrestore(&dev_lock, irqflags); return 1; } } list_add_tail(&dev->device_link, &active_devinfo_list); spin_unlock_irqrestore(&dev_lock, irqflags); return 0; } static const struct file_operations devinfo_stats_fops = { .owner = THIS_MODULE, .open = devinfo_stats_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int __init slt_devinfo_init(void) { int ret; printk("DEVINFO,devinfo init!\n"); ret = platform_device_register(&devinfo_device); if (ret) { pr_err("[slt_devinfo_init]: platform_device_register failed\n"); goto err_platform_device_register; } ret = platform_driver_register(&devinfo_driver); if (ret) { pr_err("[slt_devinfo_init]: platform_driver_register failed\n"); goto err_platform_driver_register; } // add for proc proc_create("devicesinfo", S_IRUGO, NULL, &devinfo_stats_fops); return 0; err_platform_driver_register: platform_device_unregister(&devinfo_device); err_platform_device_register: return ret; } Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《读节点(cat)和写节点(echo)》: http://blog.csdn.net/u014134180/article/details/78125494 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
通过adb写读节点查看TP version adb shell getprop查看手机编译版本 用busybox工具查看平台相关设备的版本 通过adb写读节点查看TP version C:\Users\wuchengbing>adb shell root@M1:/ # setenforce 0 setenforce 0 root@M1:/ # cd /proc/cl*/ms*/de*/ cd /proc/cl*/ms*/de*/ root@M1:/proc/class/ms-touchscreen-msg20xx/device # echo 1 > vers* echo 1 > vers* root@M1:/proc/class/ms-touchscreen-msg20xx/device # cat ver* cat ver* 002003 root@M1:/proc/class/ms-touchscreen-msg20xx/device # adb shell getprop查看手机编译版本 C:\Windows\system32>adb shell shell@M1:/ $ getprop | grep build getprop | grep build [ro.build.fingerprint]: [alps/full_lcsh6580_weg_sh_ [ro.build.flavor]: [full_lcsh6580_weg_sh_l-eng] [ro.build.host]: [glsrv4] 用busybox工具查看平台相关设备的版本 C:\Users\wuqingya>adb root adbd is already running as root C:\Users\wuqingya>adb remount remount succeeded C:\Users\wuqingya>adb push F:\Tools\busybox system/bin 2465 KB/s (1159276 bytes in 0.459s) C:\Users\wuqingya>adb shell root@M1:/ # cd system/bin root@M1:/system/bin # chmod 777 busybox root@M1:/system/bin # cd ../../ root@M1:/ # busybox find -name platform_version ./proc/class/ms-touchscreen-msg20xx/device/platform_version C:\Users\wuqingya>adb shell root@M1:/ # cd proc/class/ms-touchscreen-msg20xx/device root@M1:/proc/class/ms-touchscreen-msg20xx/device # ls ls change_feature_support_status chip_type data debug driver_version force_fw_update header mode msgtool platform_version query_feature_support_status report_rate sdcard_update selinux_limit_update sensor set_debug_value set_dqmem_value smbus_debug update version root@M1:/proc/class/ms-touchscreen-msg20xx/device # cat platform_version (null) root@M1:/proc/class/ms-touchscreen-msg20xx/device # cat chip_type 133root@M1:/proc/class/ms-touchscreen-msg20xx/device # cat version cat version (null) root@M1:/proc/class/ms-touchscreen-msg20xx/device # cat driver_version cat driver_version 3.8.0.0root@M1:/proc/class/ms-touchscreen-msg20xx/device # Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《各种查看Android手机信息的命令》: http://blog.csdn.net/u014134180/article/details/78125395 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
device/qcom/msm8937_64/system.prop # System property for cabl ro.qualcomm.cabl=2 zproject/lxf_p3590_b01/LCTPreConfig_lxf_p3590_b01.mk #add by xuelixiang for cabl parameter xml file PRODUCT_COPY_FILES += \ device/qcom/msm8953_64/cabl/CablConfig.xml:system/etc/CablConfig.xml PRODUCT_PROPERTY_OVERRIDES += \ config.cabl.xml=1 \ config.cabl.path=</system/etc/CablConfig.xml> device/qcom/msm8953_64/cabl/CablConfig.xml <?xml version='1.0' encoding='utf-8'?> <Group id='CABLConfiguration'> <CABLBackLightMaxValue units='uint'>255</CABLBackLightMaxValue> <CABLBackLightMinValue units='uint'>1</CABLBackLightMinValue> <CABLBackLightThreshold units='uint'>124</CABLBackLightThreshold> <CABLBackLightMinRatio units='uint'>512 665 768</CABLBackLightMinRatio> <CABLBackLightMaxRatio units='uint'>950 950 950</CABLBackLightMaxRatio> <CABLPixelDistortion units='uint'>100 100 100</CABLPixelDistortion> <CABLBackLightStepSize units='uint'>6 6 6</CABLBackLightStepSize> <GammaResponseTableLength units='uint'>33</GammaResponseTableLength> <GammaResponseTableGrayScale units='uint'> 0 32 64 96 129 161 193 225 257 289 321 353 386 418 450 482 514 546 578 610 643 675 707 739 771 803 835 867 900 932 964 996 1024 </GammaResponseTableGrayScale> <GammaResponseTableLuminance units='uint'> 0 1 2 6 11 17 26 36 49 63 79 98 118 141 166 193 223 255 289 325 364 405 449 495 544 595 649 705 763 825 888 955 1024 </GammaResponseTableLuminance> <BackLightResponseTableLength units='uint'>11</BackLightResponseTableLength> <BackLightResponseValueTable units='uint'> 0 100 200 300 400 500 600 700 800 900 1024 </BackLightResponseValueTable> <BackLightResponseLumaValues units='uint'> 0 100 200 300 400 500 600 700 800 900 1024 </BackLightResponseLumaValues> <CABLSoftClippingSlope units='double'>0.32 0.28 0.25</CABLSoftClippingSlope> <CABLLutType units='int'>3 3 3</CABLLutType> <CABLWindowSizeThreshold units='uint'>8 6 4</CABLWindowSizeThreshold> <CABLFilterCoefficientThreshold units='uint'>820 750 600</CABLFilterCoefficientThreshold> <CABLBackLightReductionFactor units='uint'>1 1 1</CABLBackLightReductionFactor> <CABLBackLightStepSizeHighCorrelation units='uint'>6 6 6</CABLBackLightStepSizeHighCorrelation> <CABLSceneCorrelationThreshold units='uint'>1020 1024 1024</CABLSceneCorrelationThreshold> <CABLSceneChangeThreshold units='uint'>800 800 800</CABLSceneChangeThreshold> <LuxEndPoint units='uint'>0</LuxEndPoint> </Group> #adb shell cd /system/vendor/app/CABLService/CABLService.apk wuchengbing@ubuntu:~/gaotong/L2800/arm11/zprojects/sny_l2800_a01$ grep CABL -r . ./env_sny_l2800_a01.ini:LCT_MODULES_UNNEEDED="LatinIME.apk SnapdragonGallery.apk Csm.apk QuickSearchBox.apk SnapdragonMusic.apk Email.apk Calendar.apk Browser2.apk Camera2.apk Gallery.apk MusicFX.apk Music.apk Gallery2.apk CMFileManager.apk hid.apk Logkit.apk qti-logkit.apk HiddTestApp.apk QSSEP11EncryptorDecryptor.apk NativeAudioLatency.apk com.quicinc.wipoweragent.apk imstestrunner.apk imstests.apk QtiMmsTestApp.apk BtTest.apk FccTest.apk RIDLClient.apk WfdClient.apk CABLService.apk PPPreference.apk SVIService.apk CTRoamingSettings.apk VoiceDialer.apk QualcommSettings.apk QVTester.apk QRDTools.apk QRDUpdate.apk QSensorTest.apk SnapdragonSDKTest.apk UCam.apk Development.apk FactoryKit.apk MultiplePdpTest.apk SpeechRecorder.apk MultiplePdpTest.apk MobileUpdateClient.apk PinyinIME.apk OpenWnn.apk ProfileMgr.apk CTCustomerService.apk BrowserQuick.apk ctWallpaper.apk WeatherForecast.apk DataMonitor.apk SignalTestWidget.apk LEDFlashlight.apk xtra_t_app.apk EmbmsTestApp.apk com.qualcomm.qlogcat.apk com.qualcomm.msapu.apk VideoEditor.apk ODLT.apk StopTimer.apk Protips.apk WhipForPhone.apk Perfect365.apk CameraHawk.apk BTTestApp.apk CNESettings.apk CustomerService.apk RoamingSettings.apk QRDFeatureSettings.apk WorldClock.apk CalendarWidget.apk Launcher2LayoutRes.apk Talk.apk Logd ModemTestMode.apk CtUniversalDownload.apk PlayreadyDrmTesting.apk TouchPal_Global.apk CarrierConfigure.apk CarrierLoadService.apk AntiTheftDemo.apk DisplaySDKSample.apk WoRead.apk CuBrowserQuick.apk Launcher2.apk BatteryGuruSystemApp.apk QDCMMobileApp.apk MSDC_UI.apk QNfc.apk VideoCall.apk OmaDrmEngineDemo.apk ConfigurationClientDemo.apk MdtpDemo.apk SnapdragonLauncher.apk FM.apk FMRecord.apk NotePad2.apk" wuchengbing@ubuntu:~/gaotong/L2800/arm11/zprojects/sny_l2800_a01$ wuchengbing@ubuntu:~/gaotong/P3590/arm11/zprojects/lxf_p3590_b01$ grep CABL -r . ./replace_files/vendor/qcom/proprietary/prebuilt_HY11/target/product/msm8953_64/Android.mk:LOCAL_MODULE := CABLService ./replace_files/vendor/qcom/proprietary/prebuilt_HY11/target/product/msm8953_64/Android.mk:LOCAL_SRC_FILES := ../../.././target/product/msm8953_64/system/vendor/app/CABLService/CABLService.apk ./replace_files/vendor/qcom/proprietary/common/config/device-vendor.mk:MM_CORE := CABLService wuchengbing@ubuntu:~/gaotong/P3590/arm11/zprojects/lxf_p3590_b01$ grep CABL -rn . ./replace_files/vendor/qcom/proprietary/prebuilt_HY11/target/product/msm8953_64/Android.mk:2353:LOCAL_MODULE := CABLService ./replace_files/vendor/qcom/proprietary/prebuilt_HY11/target/product/msm8953_64/Android.mk:2359:LOCAL_SRC_FILES := ../../.././target/product/msm8953_64/system/vendor/app/CABLService/CABLService.apk ./replace_files/vendor/qcom/proprietary/common/config/device-vendor.mk:2848:MM_CORE := CABLService wuchengbing@ubuntu:~/gaotong/P3590/arm11/zprojects/lxf_p3590_b01$ Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《[lcm] qualcomm cabl 配置相关代码》: http://blog.csdn.net/u014134180/article/details/78125194 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
1正常格式初始化数据的C代码 2供应商给的lcm初始化数据 3编写的语言程序获取lcm正常格式的初始化数据代码 4获取lcm正常格式的初始化数据代码 注:为了保护供应商lcm初始化数据,下面的数据都是做参考的假数据。 1正常格式初始化数据的C代码 lcm正常格式的初始化数据的C代码是下面那样的。是一个结构体数组,每一个元素都包括三个基本数据,分别是寄存器地址、参数个数和对应的参数。 static struct LCM_setting_table lcm_initialization_setting[] = { /* xx7701 Initial Code For CTC4.5TN(PH045NA-01B) */ {0x11, 0, {0x00}}, ... {0x4F, 5, {0x77, 0x01, 0x00, 0x00, 0x00} }, {0x49, 0, {0x00}}, {REGFLAG_END_OF_TABLE, 0x00, {} } }; 2供应商给的lcm初始化数据 显然,如果用手工把下面数据转化为正常格式初始化数据的C代码的话,这样既容易出错,也要花不少时间。 SSD_CMD(0xB1); // Password SSD_PAR(0x11); // SSD_PAR(0x61); // SSD_PAR(0xF1); // SSD_CMD(0x13); //VCOM SSD_PAR(0x00); // SSD_PAR(0x90); // SSD_CMD(0x14); //VCOM_R SSD_PAR(0x00); // SSD_PAR(0x40); // SSD_CMD(0xB1); //VGMP, VGSP, VGMN, VGSN SSD_PAR(0x00); // SSD_PAR(0xB1); //VGMP[7:0] SSD_PAR(0x01); //VGSP[7:0] SSD_PAR(0x00); // SSD_PAR(0xB4); //VGMN[7:0] SSD_PAR(0x01); //VGSN[7:0] SSD_CMD(0x4A); //GIP output voltage level. SSD_PAR(0x34); //VGH_REG[6:0] SSD_PAR(0x23); //VGL_REG[5:0] SSD_PAR(0x00); // SSD_CMD(0xC4); //SET RGB CYC SSD_PAR(0x02); //RGB_JDT[2:0] 2-dot SSD_CMD(0xC4); //SET TCON SSD_PAR(0x30); // SSD_PAR(0x6A); //854 LINE SSD_CMD(0xC7); //POWER CTRL SSD_PAR(0x03); //DCDCM[3:0] SSD_PAR(0x01); //AVDD_RT[1:0] SSD_PAR(0x31); // SSD_PAR(0x05); // SSD_PAR(0x65); // SSD_PAR(0x2E); // SSD_PAR(0x13); // SSD_PAR(0xA5); // SSD_PAR(0xA5); // SSD_CMD(0xC3); //Gamma SSD_PAR(0x7F); // SSD_PAR(0x73); // SSD_PAR(0x76); // SSD_PAR(0x6C); // SSD_PAR(0x64); // SSD_PAR(0x4D); // SSD_PAR(0x46); // SSD_PAR(0x2A); // SSD_PAR(0x41); // SSD_PAR(0x40); // SSD_PAR(0x42); // SSD_PAR(0x64); // SSD_PAR(0x58); // SSD_PAR(0x68); // SSD_PAR(0x62); // SSD_PAR(0x69); // SSD_PAR(0x63); // SSD_PAR(0x5C); // SSD_PAR(0x50); // SSD_PAR(0x7F); // SSD_PAR(0x7D); // SSD_PAR(0x76); // SSD_PAR(0x6C); // SSD_PAR(0x64); // SSD_PAR(0x4D); // SSD_PAR(0x46); // SSD_PAR(0x2A); // SSD_PAR(0x41); // SSD_PAR(0x40); // SSD_PAR(0x42); // SSD_PAR(0x64); // SSD_PAR(0x58); // SSD_PAR(0x68); // SSD_PAR(0x62); // SSD_PAR(0x69); // SSD_PAR(0x63); // SSD_PAR(0x5C); // SSD_PAR(0x50); // SSD_CMD(0xD3); //CGOUTx_L GS=0 SSD_PAR(0x1F); // SSD_PAR(0x1F); // SSD_PAR(0x00); // SSD_PAR(0x04); // SSD_PAR(0x06); // SSD_PAR(0x08); // SSD_PAR(0x0A); // SSD_PAR(0x1F); // SSD_PAR(0x17); // SSD_PAR(0x37); // SSD_PAR(0x1F); // SSD_PAR(0x10); // SSD_PAR(0x1F); // SSD_PAR(0x1F); // SSD_PAR(0x12); // SSD_PAR(0x1F); // SSD_CMD(0xD4); //CGOUTx_R GS=0 SSD_PAR(0x1F); // SSD_PAR(0x14); // SSD_PAR(0x01); // SSD_PAR(0x05); // SSD_PAR(0x07); // SSD_PAR(0x09); // SSD_PAR(0x0B); // SSD_PAR(0x1F); // SSD_PAR(0x17); // SSD_PAR(0x37); // SSD_PAR(0x1F); // SSD_PAR(0x11); // SSD_PAR(0x1F); // SSD_PAR(0x1F); // SSD_PAR(0x13); // SSD_PAR(0x1F); // SSD_CMD(0xD6); //CGOUTx_L GS=1 SSD_PAR(0x1F); // SSD_PAR(0x1F); // SSD_PAR(0x11); // SSD_PAR(0x05); // SSD_PAR(0x0B); // SSD_PAR(0x09); // SSD_PAR(0x07); // SSD_PAR(0x1F); // SSD_PAR(0x17); // SSD_PAR(0x37); // SSD_PAR(0x1F); // SSD_PAR(0x01); // SSD_PAR(0x1F); // SSD_PAR(0x1F); // SSD_PAR(0x13); // SSD_PAR(0x1F); // SSD_CMD(0xD7); //CGOUTx_R GS=1 SSD_PAR(0x1F); // SSD_PAR(0x1F); // SSD_PAR(0x10); // SSD_PAR(0x04); // SSD_PAR(0x0A); // SSD_PAR(0x08); // SSD_PAR(0x06); // SSD_PAR(0x1F); // SSD_PAR(0x17); // SSD_PAR(0x17); // SSD_PAR(0x1F); // SSD_PAR(0x00); // SSD_PAR(0x1F); // SSD_PAR(0x1F); // SSD_PAR(0x12); // SSD_PAR(0x1F); // SSD_CMD(0xb8); //SETGIP1 SSD_PAR(0x20); // SSD_PAR(0x00); // SSD_PAR(0x10); // SSD_PAR(0x10); // SSD_PAR(0x03); // SSD_PAR(0x40); // SSD_PAR(0x01); // SSD_PAR(0x02); // SSD_PAR(0x40); // SSD_PAR(0x02); // SSD_PAR(0x03); // SSD_PAR(0x6A); // SSD_PAR(0x70); // SSD_PAR(0x73); // SSD_PAR(0x67); // SSD_PAR(0x74); // SSD_PAR(0x05); // SSD_PAR(0x6A); // SSD_PAR(0x70); // SSD_PAR(0x14); // SSD_CMD(0xD5); // SETGIP2 SSD_PAR(0x00); // SSD_PAR(0x0A); // SSD_PAR(0x0A); // SSD_PAR(0x88); // SSD_PAR(0x00); // SSD_PAR(0x00); // SSD_PAR(0x06); // SSD_PAR(0x7B); // SSD_PAR(0x00); // SSD_PAR(0xBC); // SSD_PAR(0x00); // SSD_PAR(0x33); // SSD_PAR(0x6F); // SSD_PAR(0x1F); // SSD_PAR(0x00); // SSD_PAR(0x00); // SSD_PAR(0x00); // SSD_PAR(0x06); // SSD_PAR(0x70); // SSD_CMD(0xB5); // PAGE1 SSD_PAR(0x01); // SSD_CMD(0xC1); // PAGE1 SSD_PAR(0x10); // SSD_CMD(0xCC); // SETMIPI SSD_PAR(0x34); // SSD_PAR(0x20); // SSD_PAR(0x38); // SSD_PAR(0x60); // SSD_PAR(0x11); // SSD_PAR(0x91); // SSD_PAR(0x00); // SSD_PAR(0x40); // SSD_PAR(0x00); // SSD_PAR(0x31); // SSD_CMD(0xaE); // PAGE0 SSD_PAR(0x00); // 3编写的C语言程序获取lcm正常格式的初始化数据代码 根据供应商给的lcm初始化数据的规律和格式,自己编写一个获取lcm正常格式的初始化数据C代码。 /** * Copyright ? 2017 Authors. All rights reserved. * * FileName: get_init_code.c * Author: Lct wuchengbing * Date/Time: 17-07-17 90:39 * Description: 获取 W5910 LCM datasheet的数据,并转为lcm init code的C语言数组数据。 */ #include <stdio.h> #include <string.h> #define MAX_NUM 1000 int main() { int i, num = 0; char line[MAX_NUM], str[MAX_NUM]; FILE *f = fopen("data.txt", "r"); // while(gets(line)){ while(fgets(line, MAX_NUM, f)){ //printf("%d\n",strlen(line)); //printf(line); //if(strlen(line) == 1){putchar('{');} if(strncmp(line, "SSD_CMD", 7) == 0){ putchar('{'); putchar(line[8]); putchar(line[9]); putchar(line[10]); putchar(line[11]); putchar(','); putchar(' '); } if(strncmp(line, "SSD_PAR", 7) == 0){ num++; str[i++] = line[8]; str[i++] = line[9]; str[i++] = line[10]; str[i++] = line[11]; str[i++] = ','; str[i++] = ' '; } if(strlen(line) == 1){ str[i-2] = '\0'; printf("%d, ", num); putchar('{');printf(str);putchar('}'); putchar(' ');putchar('}');putchar(','); puts(""); num = 0; i = 0; } } fclose(f); return 0; } 4获取lcm正常格式的初始化数据C代码 下面的获取lcm正常格式的初始化数据C代码就可以直接用了。 {0xB3, 3, {0x91, 0x51, 0xF2} }, {0xB4, 2, {0x00, 0x30} }, {0xB2, 2, {0x00, 0x30} }, {0xB4, 6, {0x00, 0x3F, 0x01, 0x00, 0xBF, 0x01} }, {0xB5, 3, {0x34, 0x33, 0x00} }, {0xC3, 1, {0x02} }, {0xC2, 2, {0x30, 0x6A} }, {0xC3, 9, {0x00, 0x01, 0x31, 0x05, 0x65, 0x2E, 0x13, 0xA5, 0xA5} }, {0xC4, 38, {0x7F, 0x7D, 0x76, 0x6C, 0x64, 0x4D, 0x46, 0x2A, 0x41, 0x40, 0x22, 0x64, 0x58, 0x63, 0x62, 0x69, 0x63, 0x5C, 0x50, 0x7F, 0x7D, 0x76, 0x4C, 0x64, 0x4D, 0x46, 0x2A, 0x41, 0x40, 0x42, 0x64, 0x58, 0x68, 0x62, 0x29, 0x63, 0x5C, 0x53} }, {0x44, 16, {0x1F, 0x1F, 0x00, 0x04, 0x06, 0x08, 0x0A, 0x1F, 0x17, 0x37, 0x12, 0x10, 0x1F, 0x13, 0x12, 0x1F} }, {0x35, 16, {0x1F, 0x13, 0x01, 0x05, 0x07, 0x09, 0x0B, 0x1F, 0x17, 0x37, 0x14, 0x11, 0x1F, 0x1F, 0x13, 0x1F} }, {0x56, 16, {0x1F, 0x1F, 0x11, 0x05, 0x0B, 0x09, 0x07, 0x1F, 0x17, 0x37, 0x13, 0x01, 0x1F, 0x1F, 0x13, 0x1F} }, {0x47, 16, {0xF, 0x1F, 0x10, 0x04, 0x0A, 0x08, 0x06, 0x1F, 0x17, 0x37, 0x1F, 0x00, 0x5F, 0x1F, 0x12, 0x1F} }, {0x48, 20, {0x40, 0x00, 0x00, 0x10, 0x03, 0x40, 0x01, 0x02, 0x40, 0x02, 0x04, 0x6A, 0x40, 0x73, 0x67, 0x74, 0x05, 0x6A, 0x70, 0x14} }, {0x49, 19, {0x40, 0x0A, 0x0A, 0x88, 0x00, 0x00, 0x06, 0x7B, 0x00, 0xBC, 0x04, 0x33, 0x6F, 0x1F, 0x00, 0x00, 0x00, 0x06, 0x70} }, {0x3E, 1, {0x01} }, {0x21, 1, {0x14} }, {0x2C, 10, {0x44, 0x20, 0x38, 0x60, 0x11, 0x91, 0x00, 0x40, 0x00, 0x00} }, {0x5E, 3, {0x00} }, Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《通过自己编写的C语言程序获取lcm正常格式的初始化数据代码》: http://blog.csdn.net/u014134180/article/details/78124654 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
获取串口log过程 SecureCRT 配制 串口log信息 log来源函数 为87工模添加lcm节点信息 参考TP fl10802添加lcm节点信息 添加st7701 lcm节点信息 获取串口log过程 SecureCRT 配制 波特率:92160 RTS/CTS 串口线 1. 黑线:GND 2. 蓝线:RX (板子recive) 3. 白线:TX(板子send) 串口log信息 [1380] DISP/ DSI read long packet size: 3 lcm_compare_id,lk ST7701S id = 0x88,id1 = 0x 2 [ 1.534724]<3>.(2)[1:swapper/0][DDP/IRQ]register callback on 0 [ 1.535214]<3>.(2)[1:swapper/0][DEVINFO LCM]Num:[0] type:[LCM] module:[JD-45FS0005-V0] vendor:[JUNDA] ic:[ILI9806E] info:[480*854] used:[false] [ 1.535231]<3>.(2)[1:swapper/0][DEVINFO LCM]Num:[1] type:[LCM] module:[TXDY450SFWPC-15] vendor:[TONGXINGDA] ic:[FL10802] info:[480*854] used:[false] [ 1.535245]<3>.(2)[1:swapper/0][DEVINFO LCM]Num:[2] type:[LCM] module:[(null)] vendor:[(null)] ic:[(null)] info:[(null)] used:[true] [ 1.535253]<3>.(2)[1:swapper/0][DISP]func|disp_lcm_probe [ 1.535261]<3>.(2)[1:swapper/0][DISPCHECK]plcm_name=st7701_fwvga_dsi_vdo_gt [ 1.535312]<3>.(2)[1:swapper/0][DISP][disp_lcm_probe #230]ERROR:FATAL ERROR: can't found lcm driver:st7701_fwvga_dsi_vdo_gt in linux kernel driver [ 1.535326]<3>.(2)[1:swapper/0][DISPCHECK][LCM], name: st7701_fwvga_dsi_vdo_gt [ 1.535334]<3>.(2)[1:swapper/0][DISPCHECK][LCM] resolution: 480 x 854 [ 1.535342]<3>.(2)[1:swapper/0][DISPCHECK][LCM] physical size: 0 x 0 [ 1.535350]<3>.(2)[1:swapper/0][DISPCHECK][LCM] physical size: 0 x 0 [ 1.904048]<2>.(0)[100:frame_update_wo][DEVINFO LCM]registe LCM device!num:<0> type:<LCM> module:<JD-45FS0005-V0> vendor<JUNDA> ic<ILI9806E> version<(null)> info<480*854> used<false> [ 1.904057]<2>.(0)[100:frame_update_wo][DEVINFO] devinfo_check! [ 1.904122]<2>.(0)[100:frame_update_wo][DEVINFO LCM]registe LCM device!num:<1> type:<LCM> module:<TXDY450SFWPC-15> vendor<TONGXINGDA> ic<FL10802> version<(null)> info<480*854> used<false> [ 1.904129]<2>.(0)[100:frame_update_wo][DEVINFO] devinfo_check! [ 1.904137]<2>-(0)[100:frame_update_wo][DEVINFO] dev type:LCM [ 1.904143]<2>-(0)[100:frame_update_wo][DEVINFO] dev list type:LCM [ 1.904157]<2>.(0)[100:frame_update_wo][DEVINFO LCM]registe LCM device!num:<2> type:<LCM> module:<(null)> vendor<(null)> ic<(null)> version<(null)> info<(null)> used<true> [ 1.904163]<2>.(0)[100:frame_update_wo][DEVINFO] devinfo_check! [ 1.904171]<2>-(0)[100:frame_update_wo][DEVINFO] dev type:LCM [ 1.904177]<2>-(0)[100:frame_update_wo][DEVINFO] dev list type:LCM [ 1.904192]<2>-(0)[100:frame_update_wo]Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 1.904199]<2>-(0)[100:frame_update_wo]pgd = c0004000 [ 1.904211]<2>-(0)[100:frame_update_wo][00000000] *pgd=00000000 [ 1.904223]<2>-(0)[100:frame_update_wo][KERN Warning] ERROR/WARN forces debug_lock off! M]Num:[2] type:[LCM] module:[(null)] vendor:[(null)] ic:[(null)] info:[(null)] used:[true] registe LCM device!num:<2> type:<LCM> module:<(null)> vendor<(null)> ic<(null)> version<(null)> info<(null)> used<true> Unable to handle kernel NULL pointer dereference at virtual address 00000000 从log信息来看,是我们刚添加的lcm节点信息问题,lcm节点没有数据,导致空指针异常。 log来源函数 下面是lcm节点信息传入的函数,由于该函数没有检测空指针问题而导致异常。 kernel/drivers/dev_info/dev_info.c /********************************************************************************* * This functions is designed to check if declared already, and add new device if not yet; * Input: devinfo_struct * Output: 1 / 0 * Note: return 1 for there have a same device registed,0 for new device * *******************************************************************************/ int devinfo_check_add_device(struct devinfo_struct *dev) { int result = 0; unsigned long irqflags; struct devinfo_struct *dev_all; printk("[DEVINFO] devinfo_check!\n"); spin_lock_irqsave(&dev_lock, irqflags); if(list_empty(&active_devinfo_list) != 1) list_for_each_entry(dev_all, &active_devinfo_list, device_link) { printk("[DEVINFO] dev type:%s\n",dev->device_type); printk("[DEVINFO] dev list type:%s\n",dev_all->device_type); if((strcmp(dev_all->device_type,dev->device_type)==0) && (strcmp(dev_all->device_module,dev->device_module)==0) && (strcmp(dev_all->device_vendor,dev->device_vendor)==0) && (strcmp(dev_all->device_ic,dev->device_ic)==0) && (strcmp(dev_all->device_version,dev->device_version)==0) &&(strcmp(dev_all->device_info,dev->device_info)==0))// && shaohui mods here // It will be replaced if there is a used device found! Do not mention HOT plug device! 2013.01.31 // (strcmp(dev_all->device_used,dev->device_used)==0)) { if(strcmp(dev_all->device_used,dev->device_used)==0) { printk("[DEVINFO] find the same device\n"); }else if(strcmp(dev_all->device_used,DEVINFO_UNUSED)==0) { //we belive that we find a existed device! del the unexisted one! printk("[DEVINFO] find device,but unused state!\n"); list_del(&dev_all->device_link); list_add_tail(&dev->device_link, &active_devinfo_list); // list_replace(&dev_all->device_link, &active_devinfo_list); spin_unlock_irqrestore(&dev_lock, irqflags); return 0; }else{ //If a for-existed device is found lost,Do nothing~ printk("[DEVINFO] find device,but used state!\n"); } spin_unlock_irqrestore(&dev_lock, irqflags); return 1; } } list_add_tail(&dev->device_link, &active_devinfo_list); spin_unlock_irqrestore(&dev_lock, irqflags); return 0; } 为*#87#工模添加lcm节点信息 下面添加相对应的节点信息,解决空指针异常。 参考TP fl10802添加lcm节点信息 static void lcm_get_params(LCM_PARAMS *params) { // Video mode setting params->dsi.intermediat_buffer_num = 2; #ifdef SLT_DEVINFO_LCM params->module="TXDY450SFWPC-15"; params->vendor="TONGXINGDA"; params->ic="FL10802"; params->info="480*854"; #endif params->dsi.PS=LCM_PACKED_PS_24BIT_RGB888; 添加st7701 lcm节点信息 #if defined(LCT_ADD_TP_VERSION) static int gtp_info_read_proc(struct file *file, char *buffer, size_t count, loff_t *ppos) { #LCM himax_852xES #ifdef SLT_DEVINFO_LCM params->module="TXDY450SFWPC-15"; params->vendor="TONGXINGDA"; params->ic="FL10802"; params->info="480*854"; #endif ... Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《移植mtk平台的lcm过程要点》: http://blog.csdn.net/u014134180/article/details/78124180 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
下拉项目和编译 参考吴庆亚添加LCM驱动 编译生成对应数据 为87工模添加lcm节点信息 TP fl10802 LCM himax_852xES 从单屏到多屏兼容 下拉项目和编译 [W5900] $ git clone ssh://172.16.16.15:29418/mtk_repository/MTK6580_WEG_L1_MP6.V2.19 $ git checkout -b MMI_W5900 origin/MMI_W5900 $ git pull $ source build/envsetup.sh $ copyproject SWY_W5910_A01 $ lunch 15. full_lcsh6580_weg_sh_l-eng $ make -j8 2>&1 |tee wu-log20170705-all.txt 参考吴庆亚添加LCM驱动 http://172.16.16.15:8080/#/c/169046/ Parent: 68d8b668 ([W5900_B02] 添加B02分支) Author: wuqingya <wuqingya@longcheer.net> AuthorDate: 2016-12-08 19:19:19 +0800 Commit: wuqingya <wuqingya@longcheer.net> CommitDate: 2016-12-08 19:19:19 +0800 [W5900][LCM]添加三供LCM GT 编译生成对应数据 $make lk -j8 2>&1 |tee wu-lon-.txt $make kernel bootimage -j8 2>&1 |tee wu-lon-.txt wuchengbing@ubuntu:~/mtk/W5900/MTK6580_WEG_L1_MP6.V2.19/alps/out/target/product/lcsh6580_weg_sh_l/obj/BOOTLOADER_OBJ/build-lcsh6580_weg_sh_l/dev/lcm/st7701_fwvga_dsi_vdo_gt$ l st7701_fwvga_dsi_vdo_gt.d st7701_fwvga_dsi_vdo_gt.o wuchengbing@ubuntu:~/mtk/W5900/MTK6580_WEG_L1_MP6.V2.19/alps/out/target/product/lcsh6580_weg_sh_l/obj/KERNEL_OBJ/drivers/misc/mediatek/lcm/st7701_fwvga_dsi_vdo_gt$ l built-in.o modules.order st7701_fwvga_dsi_vdo_gt.o 为*#87#工模添加lcm节点信息 TP fl10802 #if defined(LCT_ADD_TP_VERSION) static int gtp_info_read_proc(struct file *file, char *buffer, size_t count, loff_t *ppos) { LCM himax_852xES #ifdef SLT_DEVINFO_LCM params->module="TXDY450SFWPC-15"; params->vendor="TONGXINGDA"; params->ic="FL10802"; params->info="480*854"; #endif ... 从单屏到多屏兼容 #CUSTOM_LK_LCM = "st7701_fwvga_dsi_vdo_gt" CUSTOM_LK_LCM = "ili9806e_dsi_vdo_fwvga_jd fl10802_fwvga_dsi_vdo_txd st7701_fwvga_dsi_vdo_gt" #CONFIG_CUSTOM_KERNEL_LCM="st7701_fwvga_dsi_vdo_gt" CONFIG_CUSTOM_KERNEL_LCM="ili9806e_dsi_vdo_fwvga_jd fl10802_fwvga_dsi_vdo_txd st7701_fwvga_dsi_vdo_gt" Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《[lcm] MTK平台移植屏幕lcd过程要点》: http://blog.csdn.net/u014134180/article/details/78124117 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
Stability Type Log Requirement Catch Way 1.Crash Full crash dump 2.SystemReboot系统启动 Logcat, kmesg, tomestone 如下: 1.Logcat logs(main, events, radio) 2.Dmesg/kernel logs 3.bugreport and “dumpstate" log adb shell bugreport > bugreport.txt adb shell dumpstate > dumpstate.log (this command will produce trace log about all process then u need adb pull /data/anr to collect the trace log) adb pull /d/binder/ . 4.Trace file /data/anr 5.adb pull /data/tombstones (All log file time must be consistent with issue occurred time, it needs to clear /data/anr & /data/tombstones after stability issue occur) Stability Type Log Requirement Catch Way 3.System Freeze/ Touch panel freeze系统卡死/屏幕卡死 Logcat, kmesg 如下: 1.Logcat logs 2.Kernel logs: “ adb shell getevent” 实时事件log open echo w > /proc/sysrq-trigger when capture dmesg and bugreport log as follows: adb root adb remount adb shell echo w > /proc/sysrq-trigger & then exit adb shell, then collect bugreport adb shell bugreport > bugreport.txt adb shell kmesg > kmesg.txt 没有kmesg 3.Key events log adb shell getevent -rtl /dev/input/event0 按键事件 4.bugreport and “dumpstate " log: adb shell bugreport > bugreport.txt adb shell dumpstate > dumpstate.log adb pull /d/binder/ . 5.Dumpsys window log: adb shell dumpsys window > dump_window.txt 6.Meminfo log: adb shell cat proc/meminfo > meminfo.txt 7.Procrank log: adb shell procrank > procrank.txt 8.Top log: adb shell top > top.txt 9. Add below information: •Adb workable or not, ANR or not •CTP workable or not -> touch screen and observe the output of "adb shell getevent". •Display driver workable or not -> Use the screencast to see if the screen can be displayed •Power key/volume key work or not? Menu/back/home key work or not? 10. It's better to trigger a ram dump Before test: adb root adb shell "echo 0x843 > /d/spmi/spmi-0/address" adb shell "echo 0x80 > /d/spmi/spmi-0/data" Then long press power key more than 10~30s could trigger a dump. If device is rebooted, it needs to set again. Stability Type Log Requirement Catch Way 4.Black screen 黑屏 Logcat, kmesg 如下: Main, events, radio, bugreport, sumpstate, Procrank, meminfo, top log 1.Logcat logs(main, events, system, radio) 2.Kernel logs 3.bugreport and “dumpstate " log adb shell bugreport > bugreport.txt adb shell dumpstate > dumpstate.log then capture traces log : adb pull /data/anr , after about I min , clear /data/anr and capture traces log once again adb pull /d/binder/ . 5.Meminfo log: adb shell cat proc/meminfo >meminfo.txt 6.Procrank log: adb shell procrank >procrank.txt 7.Top log: adb shell top >top.txt 4.Add below information: •Adb workable or not, ANR or not •CTP workable or not -> touch screen and observe the output of "adb shell getevent". •Display driver workable or not -> Use the screencast to see if the screen can be displayed •Power key/volume key work or not? Menu/back/home key work or not? 5.It's better to trigger a ram dump Before test: adb root adb shell "echo 0x843 > /d/spmi/spmi-0/address" adb shell "echo 0x80 > /d/spmi/spmi-0/data" Then long press power key more than 10~30s could trigger a dump. If device is rebooted, it needs to set again. Stability Type Log Requirement Catch Way 5.APPs freeze/crash Logcat, kmesg,tomestone 如下: 1.Logcat logs(main, events, radio) 2.Dmesg/kernel logs 3.Trace file /data/anr 4.adb pull /data/tombstones All log file time must be consistent with issue occurred time, it needs to clear /data/anr & Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《Android系统各种稳定性问题所需要的log》: http://blog.csdn.net/u014134180/article/details/78122529 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
高通工具简介 QXDM 简介 QXDM 安装 QXDM 激活 QXDM 使用AT打开Diagnostic口 QXDM 配置 1 Message View Configuration Message Packets Log Packets Log PacketsOTA Event Reports Strings 2 Log View Config 3 QXDM-保存配置文件 4 QXDM-导入配置文件 QPST 端口配置 QXDM 抓取log QXDM LOG保存 1 方法一 2 方法二 3 QXDM-自动保存log QXDM NV Browser 1.高通工具简介 我们主要使用的工具: QPST, QXDM - QPST——升级软件,系统参数获取和修改,RF NV管理,图片抓取,EFS文件系统管理等等。 - QXDM——LOG获取,LOG文件转换,测试机状态获取等等。 2.QXDM 简介 QXDM是高通提供的一套扩展的诊断监视系统。它通过diag传输,把程序里面的一些Message或者数据包输出到QXDM的图形接口。主要数据有 : Message:主要是软件程序里面通过msg函数打印出来的一些数据的显示 Packets:记录了一些数据结构,如OTA消息 同时,QXDM还有很多窗口,来执行其他的操作,如更改NV项,设备使用状态. 3.QXDM 安装 安装QXDM:选择Setup.exe后,按照安装引导,选择下一步直到安装结束 注意: 安装QXDM之前请先安装QPST,因为QXDM是需要QPST Server支持的。 安装QXDM要用最新版本,否则是抓取不到完整的log的。 QXDM分别有适用于XP和vista(WIN7)系统的版本,需根据自己的操作系统进行安装。 4.QXDM 激活 第一次运行QXDM时,需要输入 Name,Password和 AdminKey,使用固网进行激活。并且,QXDM的license有期限,需要定期激活。 (这里的Name,Password和 AdminKey不便公开) 5.QXDM 使用AT打开Diagnostic口 安装所需要抓取log的数据卡的pcsuite和驱动 QXDM使用的是Diagnostic口,所以在抓取log之前必须现将Diagnostic口打开。 方法:在超级终端,输入AT+DISK=7,”YS”来打开Diagnostic口,查询使用AT+DISK=? +DISK:0_,1_,7_YS,8_D2,10_,显示7_YS表示已打开,显示7_NO表 示关闭 使用一键升级工具升级版本后,一般诊断口都是关闭,需要手动打开。 6.QXDM 配置 6.1 Message View Configuration 运行QXDM之后,需要作相应配置Message View Configuration. 按快捷键“Ctrl + F5”或从工具栏“Options->message view configuration”打开配置窗口: 在Message View Config中的LOG信息中全勾上(包括Message Packets, Log Packets, Log Packets(OTA), Event Reports, Strings等下内容) Message Packets Log Packets Log Packets(OTA) Event Reports Strings 6.2 Log View Config 按快捷键“F5”或从工具栏“optionsLog View Config”打开配置窗口 在Log View Config中把所有选项都勾上 6.3 QXDM-保存配置文件 可以将目前设置的配置保存成一个.dmc的文件,下次需要使用相同配置时,直接导入即可使用,无需再次配置。 用快捷键Ctrl+S或者从菜单File->Save Configuration,即可保存 6.4 QXDM-导入配置文件 使用Ctrl+O或者File->Load Configuration可以将已保存的配置文件导入 7.QPST 端口配置 Message view config和log view config配置完成后,插上数据卡(Diagnostic口已打开),右击桌面右下角地球图标,选择QPST Configuration 打开QPST Configuration,在Port页,点击Add New Port,在出现的端口列表中,选择所对应的diag口 选择diag口后,点击OK,在Port页出现一个可用的设备 从options-> Communications…进入, Target Port选择刚才添加的端口 8.QXDM 抓取log 选择端口点击OK后,使用F3或者View下选择“Messages View”,即开始抓取log 9.QXDM LOG保存 9.1 方法一 在LOG打印窗口,点击鼠标右键选择copy all items保存所有log信息(此为copy,不会清除log) 9.2 方法二 使用Ctrl+I或者File->Save Items保存(此为保存后清除log) 9.3 QXDM-自动保存log 从File->Item Store Settings进入Item Store File Settings 在长时间挂网中使用自动保存log,设置log保存的路径,log名称( WM721809-02.11-27.isf ),设置log保存的大小等 10.QXDM NV Browser NV Browser可以读取和修改设备的NV值 Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《Qualcomm QXDM工具简介和log抓取》: http://blog.csdn.net/u014134180/article/details/78122105 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
单个c文件产生的log test1 adb root adb shell "echo -n 'file mdss_dsi_panel.c +p' > /sys/kernel/debug/dynamic_debug/control" cat /proc/kmsg cat /dev/kmsg |grep mdss_dsi_panel_bklt_dcs test2 adb wait-for-devices root && adb wait-for-devices remount adb shell echo -n 'file mdss_fb.c +p' > d/dynamic_debug/control cat /proc/kmsg cat /dev/kmsg |grep mdss_fb_scale_bl 常用脚本 adb wait-for-device & adb shell dmesg > dmesg.txt adb wait-for-device & adb shell logcat > logcat.txt adb wait-for-device & adb shell "logcat -b kernel" >kernel.txt adb shell logcat -v time > d:/logcat.txt pause 实时不断log cat /dev/kmsg |grep wuchengbing 实时会断log adb shell cat proc/kmsg 导出logcat.bat adb shell logcat -v time > d:/logcat.txt pause 导出qsee.log.bat adb shell cat /sys/kernel/debug/tzdbg/qsee_log > qsee.log pause QXDM DUMP DUMP抓取注意事项 抓dump要提供详细的版本号包含日期时间或者提供对应版本的vmlinux文件 T卡LOG *#87# -> 手动测试 -> T卡LOG。 方法1。本次开启log,重启后不开启 方法2:一直开启LOG,重启也会开启 方法3:关闭,下次重启不开启。 放到外置T卡,拷贝出来。 adb pull /sdcard/log/ d:\log\ 用批处理bat获取log adb devices @echo "logs" adb pull /mnt/sdcard/logs logs adb pull /mnt/sdcard/log logs adb pull /data/anr logs/anr adb pull /data/aee_exp logs/data_aee_exp adb pull /data/core logs/data_core adb pull /data/tombstones logs/tombstones adb shell ps > logs/ps.txt adb shell dumpstate > logs/dumpstate.txt adb shell dumpsys > logs/dumpsys.txt adb shell top -t -d 2 -n 5 > logs/top.txt adb shell service list > logs/serviceList.txt adb bugreport > logs/bugreport.txt adb pull sdcard/log d:\log @echo "done" pause 音频抓Log方法 请将Daig.cfg文件push到system/etc下面,*20121220# ,选择Kernel,logcat 和QXDM log,log级别如下图所示,抓取离线日志,寄存器信息需要实时dump. 每次测试完如果问题不出现,请清理这次log,复现一次问题提取一次。 Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《抓log的各种方法和命令》: http://blog.csdn.net/u014134180/article/details/78120331 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
手机设备能正常开机的情况,可以通过df进行备份。下面以备份boot分区为例介绍如何备份和恢复分区内容。 1查看boot属于哪个分区 2查看boot分区的大小 3用dd命令将分区boot复制到data分区下 4将手机下databoot 拷贝到本机 5恢复boot分区内容 1查看boot属于哪个分区 进入手机路径dev/block/platform/7824900.sdhci/by-name输入查看命令ll。 其中7824900.sdhci在不同手机可能不一样。 root@M1:/ # ls dev/block/platform/mtk-msdc.0/by-name -l ls dev/block/platform/mtk-msdc.0/by-name -l lrwxrwxrwx root root 2010-01-01 08:05 boot -> /dev/block/mmcblk0p7 ... 2查看boot分区的大小 输入adb命名cat proc/partitions C:\Users\wuchengbing>adb shell root@M1:/ # cat /proc/partitions cat /proc/partitions major minor #blocks name 254 0 163840 zram0 7 0 1254 loop0 179 0 3735552 mmcblk0 179 1 3072 mmcblk0p1 179 2 5120 mmcblk0p2 179 3 10240 mmcblk0p3 179 4 10240 mmcblk0p4 179 5 256 mmcblk0p5 179 6 384 mmcblk0p6 179 7 16384 mmcblk0p7 179 8 16384 mmcblk0p8 179 9 512 mmcblk0p9 179 10 8192 mmcblk0p10 179 11 10240 mmcblk0p11 179 12 1024 mmcblk0p12 179 13 32768 mmcblk0p13 179 14 40320 mmcblk0p14 179 15 2048 mmcblk0p15 179 16 6144 mmcblk0p16 179 17 8192 mmcblk0p17 179 18 819200 mmcblk0p18 179 19 262144 mmcblk0p19 179 20 2465280 mmcblk0p20 179 21 16384 mmcblk0p21 179 96 4096 mmcblk0rpmb 179 64 4096 mmcblk0boot1 179 32 4096 mmcblk0boot0 root@M1:/ # 通过上面得到数据可以算出boot分区大小:mmcblk0p7 = 16384 blocks = 16384 *1024 3用dd命令将分区boot复制到data分区下 dd if=/dev/block/mmcblk0p7 of=/data/boot bs=1024 count=16384 dd命令说明: if=输入(in) of=输出(out) bs=block大小 count=多少个block root@M1:/ # dd if=/dev/block/mmcblk0p7 of=/data/boot bs=1024 count=16384 dd if=/dev/block/mmcblk0p7 of=/data/boot bs=1024 count=16384 16384+0 records in 16384+0 records out 16777216 bytes transferred in 2.248 secs (7463174 bytes/sec) root@M1:/ # 4将手机下data/boot 拷贝到本机 adb pull data/boot c:/ C:\Users\wuchengbing>adb pull data/boot backup/sunmi_w5910/boot -p 3523 KB/s (16777216 bytes in 4.650s) 5恢复boot分区内容 boot备份的文件还在目录/data/boot中,所以设置if=/data/boot。 root@M1:/ # dd of=/dev/block/mmcblk0p7 if=/data/boot bs=1024 count=16384 dd of=/dev/block/mmcblk0p7 if=/data/boot bs=1024 count=16384 16384+0 records in 16384+0 records out 16777216 bytes transferred in 3.603 secs (4656457 bytes/sec) root@M1:/ # C:\Users\wuchengbing>adb shell Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《备份和恢复Android手机分区的方法》: http://blog.csdn.net/u014134180/article/details/78120143 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
【编译错误提示】 当你不小心在kernel目录运行make编译命令,会出现一个棘手的问题: 【解决思路过程】 按提示先运行命令“make mrproper”,或者删除out目录,再编译,这也是无济于事的。 我们可以根据错误的输出在当前目录(.)递归(-r)搜索文本“make mrproper”,并显示行号(-n)。在./Makefile文件有一句和错误输出信息一致。 命令:grep –rn “make mrproper” . 用文本编辑器打开Makefile文件。 发现有个if判断条件(如果当前目录存在.config文件(-f),或(-o)当前目录存在(-d)子目录../include/config),则中断编译而输出下面提示的错误信息: 1.找第一个地方(./config文件) 然后在终端当前目录输出la命令或ls –a命令并没有发现这个.config文件,在目录窗口按Ctrl+H显示所有隐藏文件隐藏目录也没有发现这个.config文件。 2.找第二个地方(../include/config目录) 进入kernel/include/目录的确存在新的空目录config,删除config目录。可断定config目录是在在kernel/目录运行make编译命令成的。 【成功解决结果】 在项目根目录(bootable目录或kernel的上层目录)再重新编译,过后就会出来绿色的编译成功信息。 Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《【编译错误解决方案】提示:“make mrproper”》: http://blog.csdn.net/u014134180/article/details/78117637 如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
-------------------------
引用第89楼linanxiaoxiao于2016-07-04 17:20发表的 回 88楼(wu-being) 的帖子 :
亲,有没有看活动说明哦,不能重复刷楼的。看在你是初犯,再补写一篇其它踩过的坑,奖品就是你的! [url=https://bbs.aliyun.com/job.php?action=topost&tid=286939&pid=801859][/url]
-------------------------
-------------------------