- 国 籍
- 中国
- 出生地
- 湖北
- 现 居
- 北京
- 代表作品
- 梦开始的地方
- 体 重
- 56公斤
- 学 校
- 现就读于北京演艺学院
- 出生日期
- 01月01日
- 性 格
- 活泼,耍酷
- 中文名
- 刘超
- 民 族
- 汉
- 专 业
- 音乐制作,流行演唱
- 身 高
- 173公分
- 性 别
- 男
- 外文名
- super
- 星 座
- 摩羯座
- 文化程度
- 本科
-
2020-09-22 20:45:06
super 命令的功能
super 命令允许指定的用户执行脚本或其它命令如同 root 用户执行一样,或者在执行命令前针对每一个命令设定指定的 uid、gid 或候选的组。
manual 原文
SUPER(1) General Commands Manual SUPER(1) NAME super - execute commands setuid root. SYNOPSIS To execute a command: super [ -r reqpath] command [ args ] super [ -r reqpath] -o path [ args ] command [ args ] To list available commands: super [-H|-f] [-S] For usage and/or version information: super [-h] [-V] For debugging and development: super -b super -c [ superfile ] super [-d|-D|-t] [-S] [MasqOptions] [-H|-f|command...] MasqOptions: -F file -T hh:mm/dayname -G gid -U uid -M mach DESCRIPTION Super allows specified users to execute scripts (or other commands) as if they were root; or it can set the uid, gid, and/or supplementary groups on a per-command basis before executing the command. It is intended to be a secure alternative to making scripts setuid root. Super also allows ordinary users to supply commands for execution by others; these execute with the uid, gid, and groups of the user offering the command. Super consults a ``super.tab'' file to see if the user is allowed to execute the requested command. If permission is granted, super will exec pgm [ args ], where pgm is the program that is associated with this command. (Root is allowed execution by default, but can still be denied if a rule excludes root. Ordinary users are disallowed execution by default.) The most common sort of entry in a super.tab file pairs a simple command with a pgm path. But in fact, the command in the super.tab file is actually treated as a pattern, and any user-entered command that matches this pattern causes the associated pgm to be executed. If the listed pgm contains an asterisk, then the asterisk is replaced with the command entered by the user. One use of this is to let any program in a certain directory be executed by a user. For example, if the entry contains the command/pgm pairs CommandPattern Program scripts/* → /usr/local/super/* * → /usr/local/somedir/* then the translations made are User's Command Executed Program scripts/xyz → /usr/local/super/scripts/xyz xyz → /usr/local/somedir/xyz Some commands can only be run after the user enters his or her password. These commands can then be run multiple times until some expiration time, at which point the password needs to be re-entered. The list of password-requiring commands and the password durations are set in the same file that records the valid users for each command. If command is a symbolic link (or hard link, too) to the super program, then typing % command args is equivalent to typing % super command args (The command must not be super, or super will not recognize that it's being invoked via a link.) Super without any arguments will display the list of commands that may be executed by the user. For security, the following precautions are taken before executing: (a) all descriptors save 0,1,2 are closed; (b) all of the user's environment variables are discarded, save for TERM, LINES, and COLUMNS. If TERM contains any characters other than {-/:+._a-zA-Z0-9}, it is discarded. If LINES or COLUMNS contains any characters other than [0-9], it is discarded. To these are added reasonable values for: USER and LOGNAME: both are set to the username associated with the real uid of the program running under super; HOME: set to the login directory of the user running super; ORIG_USER, ORIG_LOGNAME, ORIG_HOME: the values of USER, LOGNAME, and HOME that refer to the user who invoked super. (These values are computed by super, and are not the values set by the caller, so they are a reliable description of the caller. These are normally the same values as USER, LOGNAME, and HOME, but they will differ if the super command changes uid or gid before executing the program.); IFS: set to blank, tab, newline; PATH: set to /bin:/usr/bin. SUPERCMD: set to command. additional environment variables as specified in the super.tab file (see below). (c) all signal handling is reset to the default. If Super is executed without arguments, it will print the commands that the user may execute, one command per line. Super -H prints a long-winded description of each command that the user may execute. The CmdPat is the command pattern, and FullPath is the full path that will be executed. The super.tab file can specify initial arguments that that precede any user-supplied arguments; these arguments, if any, are printed after the FullPath column. User-Defined Super.tab Files Ordinary users can supply their own super files. This lets users give well-controlled setuid/setgid access to their programs: the user who offers the program gets the assurance of safe IFS settings, safe environment variable settings, etc; and the user who executes the program knows that it will execute under the uid and gid of the offering user. If a command is entered in the form super loginname:cmd super looks for cmd in the file .supertab, in the home directory of account loginname. The cmd will be executed using the uid, gid, and supplementary groups (if any) of user loginname. The usual super options (such as -H) can be applied to a user's .supertab file. For example, help information about one command can be had by using:super -H loginname:cmd Likewise, help information about all of loginname's commands can be obtained with:super -H loginname: Links to per-user commands can be created and used in a manner similar to making symlinks to super itself. If command is a symbolic link to a user's .supertab file, and that .supertab file is (a) executable, and (b) begins with #! /path/to/super -o then the following pair are completely equivalent: % super loginname:command % command If the #!-line would be longer than the typical Unix limit of 32 characters, you can instead start the .supertab file with: #! /bin/sh # Keep this backslash -> \ exec /long/path/to/the/super/executable -o $0 ${1+"$@"} (The above takes advantage of the fact that super allows comments to be backslash-continued, but the shell doesn't.) Per-user .supertab linking works as follows: if /path/to/xyz is a symlink to some user's .supertab file, and the .supertab file begins with #! /path/to/super -o, then the shell will invoke super with arguments something like super -o /path/to/xyz [args] Super checks that /path/to/xyz is a link to a real .supertab file, and then always turns the last part of the path (here xyz) into the command to execute. ** Security Warning ** Note that if you use symlinks to a per-user .supertab file, then you must trust that the .supertab file will actually execute a super command, instead of doing something nasty. That is because super itself isn't invoked until the shell has opened the .supertab file and done whatever the .supertab file tells it to do. By contrast, the direct command super loginname:cmd doesn't involve any shell processing of the .supertab file. REGULAR OPTIONS -V Print the super version number. -S When super prompts for a password, this forces it to prompt on stdin, even if the default (/dev/tty) is readable and writable. Note: This only applies to password-type authentication — that is, the older type of authentication wherein super itself prompts for the password; PAM authentication is handled by your system's PAM modules. -f This requests a list of available commands in a terse format useful for processing by scripts. (-f stands for facts, as in ``just the facts, m'am''). -rreqpath Tells super to generate an error if the program associated with this command is not reqpath. This helps you write scripts that ensure that super only executes what they expect it to execute. See step 4 of the section, ``Creating Super Scripts'', for an example of its use. -H Causes super to print a verbose listing of the commands available to the user. It prints both the command and its translation to a program pgm. If the displayed pgm contains an asterisk, then the actual program executed is formed by replacing the asterisk with the command entered by the user. The following examples show the kinds of lines that may be displayed with the -H option: Example 1. super skill → /usr/local/bin/skill Typing super skill will execute /usr/local/bin/skill. Example 2. super {lp*} → /usr/bin/* This example contains asterisks on both the left and right sides. The left side shows the valid pattern you must match to execute the command shown on the right-hand side. Usually, the right-hand side has no asterisk, just a full path to a command to execute. If there is an asterisk present, it is replaced by the command you entered, thereby forming the actual executed command. Thus, if you type super lpxxx (where xxx is any string), super will execute /usr/bin/lpxxx. Example 3. super {co*} → /usr/bin/compress The asterisk on the left-hand side means you can enter super coxxx (where xxx is any string), but since the right-hand side doesn't contain an asterisk, coxxx will always execute /usr/bin/compress. -t This enables ``test'' mode. It does all normal checks except for those requiring user input (passwords and variables that the user must enter), but doesn't execute any command. Instead, it exits with status code 0 if the command is ok to execute, else 1. All normal error message output is generated in the usual way, but no special debug messages are generated. Thus, it is a useful means for a script to check if a command is likely to work, and hence reasonable to exec super. Let's say that a script /usr/lo‐ cal/bin/foo wants to invoke itself using super foo (See the section ``Creating Super Scripts'' for how to avoid infinite loops when doing this!) the script can use the -r option to ensure that super foo refers to the correct file, and it can use test mode to ensure that super foo is a valid command: prog=`basename $0` /usr/local/bin/super -t -r $0 $prog case $? in 0 ) exec /usr/local/bin/super -t -r $0 $prog ;; * ) echo "Super $prog doesn't work!" ... So take appropriate action ... ;; esac DEBUG AND DEVELOPMENT OPTIONS These options are useful when creating and debugging super.tab files. They have little or no value to the everyday user. With the exception of the -b option, they can be combined with the regular options, above. -b Print the names and values of built-in variables, then exit. Useful for administrators to learn the values against which builtin variables can be tested. -c[superfile] Tells super to check the syntax of the entries in the superfile, but not to execute any command. If no superfile is given, the regular super.tab is checked. The exit code is 0 if the file's syntax is ok; otherwise the exit code is 1 (and an error message is printed). After modifying a super file, you should use this option to check its integrity. Note that super -c isn't a complete check that you've correctly set up an entry, because you can create syntactically valid entries that don't do exactly what you want. Therefore, you should also use super -d cmd to make sure that the command you've entered will be executed with the correct arguments, uid, gid, umask, and so on. -d This enables debug mode, in which case (a) debugging information is printed while checking a user for validity, and (b) the command isn't actually executed. Useful to check if a new entry in the super.tab file (see below) has been handled properly. -D Same as -d, plus prints more information about variables defined in the super.tab file. -Fsuperfile This option is only used for debugging, and lets you test a superfile before installing it. No command will actually be executed.It also turns on a non-verbose debugging, showing the matched command names and reasons for accepting or rejecting the command. -Ggid This option is also used for debugging, and tells super to act as if the caller's groupid or groupname was gid. It carries the same restrictions and debug info as the -F option. -Uuid This option is also used for debugging, and tells super to act as if the caller's uid or username was uid. It carries the same restrictions and debug info as the -F option. -Mmach This option is also used for debugging, and tells super to act as if the caller's host (machine) was mach. It carries the same restrictions and debug info as the -F option. -Thh:mm/dayname This option is also used for debugging, and tells super to act as if the execution time is hh:mm/dayname. This lets you check if a time specification in the super.tab file is properly restricting execution. It carries the same restrictions and debug info as the -F option. FILES /etc/super.tab contains the list of commands that super may execute, along with the names of the user/group combinations who may execute each com mand. The valid-user line can restrict use to particular users or groups on different hosts, so a single super.tab file can be used across a network. /run/superstamps/username is used as a timestamp for the last time that the user entered his or her password. CREATING SUPER SCRIPTS You must be exceedingly careful when writing scripts for super. A surprising variety of ordinary commands can, when run setuid-root, be exploited for nasty purposes. Always make your scripts do as little as possible, and give the user as few options as possible. Think twice about side-effects and alternative uses of these scripts. For instance, make sure your script doesn't quietly invoke the user's .cshrc or similar file. Or, you might write a script to allow users to mount cd-rom's by executing mount(8). But if you don't write it carefully, a user could mount a floppy disk containing, say, a setuid-root shell. Security issues aside, here are some hints on creating super scripts: 1. Scripts must begin with #! interpreter-path. 2. Some variants of csh will not run setuid scripts unless the -b flag (force a "break" from option processing) is set: #!/bin/csh -fb Similarly, if your super.tab file starts a shell such as csh or tcsh, you may want to include the -b option in the super.tab file, so that you don't have to remember to type it on the command line every time; use a line like the following in the super.tab file: SHELL "/usr/bin/csh -fb" some_priv_user N.B. This is by way of example only; it's not a very good idea to really let somebody become root without any password check. 3. Better still, avoid csh scripts entirely -- they are harder to write safely than Bourne-shell scripts. 4. It's nice to make the super call transparent to users, so that they can type % cdmount args instead of % super cdmount args You can make a script super itself by beginning the script in the following way: #!/bin/sh prog=`basename $0` test "X$SUPERCMD" = "X$prog" || exec /usr/local/bin/super -r $0 $prog ${1+"$@"} Here, the path that is exec'd should be replaced with the path at your site that leads to super. The option -r$0 is a sanity-check option: it tells super that it's an error if ``super $prog'' doesn't execute ``$0'', ie this self-same program. (Also, see the -t option for how a script can check that super $prog will work before doing an exec super.) 5. Some programs need certain directories in the path. Your super scripts may have to add directories like /etc or /usr/etc to make commands work. For instance, SunOS 4.1 needs /usr/etc in the path before it can mount filesystems of type ``hsfs''. 6. By default, super only changes the effective uid. Some programs (e.g. exportfs under SunOS 4.1.x) require the real uid to be root. In that case, you should put an option like ``uid=root'' or ``u+g=root'' into the super.tab file. SEE ALSO super.tab(5). AUTHOR Will Deich will@ucolick.org NOTES If the super.tab file isn't owned by root, or if it is group- or world-writable, super won't run setuid-root. (If the user's real uid is root, super won't run at all; otherwise, the effective uid reverts to real uid.) There is a race condition when using password-requiring commands, but it doesn't affect security: if a user is running two copies of super simultaneously, and both processes try to update the user's password timestamp file at the same time, then it is possible for one of the super commands to fail. Workaround: a single user shouldn't execute two password-requiring super programs simultaneously. local SUPER(1)
更多相关内容 -
Delphi7用superobject解析Json数据,superobject.pas下载
2020-11-07 23:22:27Delphi读写操作JSON字符串时,需引用一个superobject.pas文件。 var jo,jt:ISuperObject; begin jo:=SO(); jt:=SO(); jo.S['姓名']:='小王'; jo.I['年龄']:=25; jo.S['性别']:='男'; jt.O['人员']:=jo; ... -
Delphi json superobject 支持XE10.3
2020-05-06 20:57:54Delphi superobject 支持XE10.3 json -
superobject1.26
2018-05-28 16:55:50superobject1.26 SuperObject.pas,superxmlparser.pas -
supersocket1.6.6源代码学习
2018-12-05 12:01:04supersocket1.6.6源代码学习。生成的类库有SuperSocket.Common.dll、SuperSocket.SocketBase.dll、SuperSocket.SocketEngine.dll、log4net.dll -
superobject 1.25
2017-05-02 17:04:30superobject 1.25 ------------------ SuperObject提供了两个类库文件SuperObject.pas,superxmlparser.pas,其中SuperObject.pas就是用于操作json数据,而superxmlparser.pas用与从XML数据中解析出json数据。 -
SuperSU-v2.79.zip
2018-05-03 14:01:00android root工具 supersu-v2.79版本。超级授权管理专业工具,它是款对Android手机进行ROOT的超级权限管理工具,超级用户访问权限管理必备利器。Super SU 原生无广告,自带简体中文,支持已ROOT设备上所有应用的超级... -
SuperSocket-master_Socket基于TCP、UDP
2019-06-27 15:07:38SuperSocket-master_Socket 、Socket、SuperSocket、TCP、UDP -
点云配准Super-4PCS
2018-11-15 11:23:53点云配准算法super-4pcs,是4pcs算法的升级版,代码来自于官网。 -
SuperSocket客户端+服务端完整demo
2018-11-09 17:36:14SuperSocket客户端+服务端完整Demo 代码,包括 net4.0运行库,比较适合新手! -
C#SuperSocket服务端与客户端通信实例
2018-09-17 12:50:18socket服务端采用SuperSocket搭建,客户端与服务端进行连接及向服务端发送消息,服务端使用业务向客户端发送消息进行通信 -
SuperSocket(服务端winform+客户端winform)
2018-11-21 16:59:32SuperSocket(服务端winform+客户端winform) 案例,可直接运行跑起来 -
SuperSocket实例程序
2018-03-20 22:29:46基于SuperSocket V1.6.1开发的示例程序,含服务端和客户端,编译无报错,运行正常。学习基于SuperSocket开发的同学值得一看 -
SuperSU-v2.82 卡刷包和apk
2018-11-24 16:25:06解压后有一个apk 是安装包,另一个zip则是SuperSU的卡刷包,发现SuperSU的官网已经不再可以访问了,所以就上传到CSDN去 -
DelphiXe10 Json解析类 superobject 支持xe10
2018-11-06 19:21:29superObject支持xe10,一直用这个习惯了,xe版本带的用的有问题 -
Delphi7下SuperObject的JSON使用方法
2017-11-27 15:40:49Json是一种轻量级数据传输格式,广泛应用互联网和各应用中,json主要采用键值对来表示数据项,多个数据项之间用逗号分隔,也可以...下面注重介绍一下在delphi中使用json,在delphi中使用json常用superobject单元文件 -
SuperSU-v2.79安装包
2018-05-24 18:38:40supersu安装,用于管理root权限,v2.79版本。 . -
super_decision操作方法(中文版、英文版、图文版)
2017-08-17 15:13:43super_decision操作方法(中文版、英文版、图文版) -
Java中super关键字及super()的使用
2020-07-06 22:52:15super关键字的使用: (1)super是一个关键字; (2)super和this很类似,我们对比着学习。 先复习一下this关键字的使用。 this关键字: this能出现在实例方法和构造方法中; this的语法是“this.”和“this()”; ...Java中super关键字及super()的使用:
1、super的使用:
(1)super是一个关键字。
(2)super和this很类似,我们对比着学习。
2、先复习一下this关键字的使用。
(1)this能出现在实例方法和构造方法中;
(2)this的语法是“this.”和“this()”;
(3)this不能出现在静态方法中;
(4)this大部分情况下是可以省略的;
(5)this.什么时候不能省略呢?
在区分局部变量和实例变量时不能省略。例如:Public void setName(String name){ this.name = name; }
(6)this()只能出现在构造方法的第一行,通过当前的构造方法去调用“本类”中的对应的构造方法,目的是:代码复用。
3、super关键字:
(1)super能出现在实例方法和构造方法中。
(2)super的语法是“super.”和“super()”。
(3) super不能出现在静态方法中。
(4) super大部分情况下是可以省略的。
(5)super.什么时候不能省略呢?
别急,我们想一下this指向的是什么,是当前对象自己。super和this类似,它指向了当前对象自己的父类型特征(也就是继承过来的那些东西)。super和this区别是:this可以看做一个引用变量,保存了该对象的地址,是当前对象整体,而super代表的是父类型特征,是子类局部的一些东西,这些继承过来的东西已经在子类里面了,你可以输出整体this,但不能输出父类型特征super。因为super指向的东西不是一个整体,没法打印输出。
System.out.println(this); //输出this.toString()的值 System.out.println(super); //编译报错,需要'.'
当在子类对象中,子类想访问父类的东西,可以使用“super.”的方式访问。例如:方法覆盖后,子类内部虽然重写了父类的方法,但子类也想使用一下父类的被覆盖的方法,此时可以使用“super.”的方式。当子类中出现和父类一样的属性或者方法,此时,你要想去调用父类的那个属性或者方法,此时“super.”不能省略。
this和super都只能在对象内部使用。
this代表当前对象本身,super代表当前对象的父类型特征。“this.”是一个实例对象内部为了区分实例变量和局部变量。
而“super.”是一个实例对象为了区分是子类的成员还是父类的成员。
父类有,子类也有,子类想访问父类的,“super.”不能省略。(6)super()只能出现在构造方法的第一行,通过当前的构造方法去调用“父类”中的对应的构造方法,目的是:创建子类对象时,先初始化父类型特征。
用通俗的话来讲,要想有儿子,得先有父亲。
我们来看下面代码:
写两个类,Animal和Cat,Cat继承Animal。//父类,Animal类 class Animal { //构造函数 public Animal() { System.out.println("Animal类的无参数构造函数执行"); } } //子类,Cat类 class Cat extends Animal{ //构造函数 public Cat() { System.out.println("Cat类的无参数构造函数执行"); } }
执行下面一行代码:
public static void main(String[] args) { Cat cat = new Cat(); }
运行输出结果为:
Animal类的无参数构造函数执行 Cat类的无参数构造函数执行
我们发现实例化一个子类的对象,也就是调用了子类的构造方法,为什么父类的无参数构造方法也执行了,并在子类构造方法执行之前就已经执行了父类的无参数构造方法,好奇怪。
刚刚在上面的super关键字的使用第6点,我已经说了,super()和this()方法一样,都只能在构造方法的第一行出现。我们猜想,难道子类的构造方法第一行有一个隐形的super()方法?答案是肯定的。
我们把子类的构造方法的第一行给它加上super():
//子类,Cat类 class Cat extends Animal{ //构造函数 public Cat() { super(); System.out.println("Cat类的无参数构造函数执行"); } }
再执行下面代码:
Cat cat = new Cat();
运行输出结果为:
Animal类的无参数构造函数执行 Cat类的无参数构造函数执行
和刚才的子类构造方法没加super()的运行结果是一样的。
所以说当子类的构造方法内第一行没有出现“super()”时,系统会默认给它加上无参数的"super()"方法。
开始讲道理:
阅读仔细的人会发现,为什么是没有“this()和super()”就写上“super()”?有“this()”就不能写上“super()”吗?那我问你,当构造方法第一行有"this()"时,你还能手动添加“super()”吗?显然不行,因为“this()”也只能出现在第一行,你不能在它前面写任何代码。所以我们又得出一个结论:构造方法中“this()”和“super()”不能同时出现,也就是“this()”和“super()”都只能出现在构造方法的第一行。上面谈的都是无参数的“super”方法,我们也可以在构造方法的第一行使用有参数的“super(父类构造函数的参数列表)”,但值得注意的是,当子类构造方法执行有参数的“super(参数列表)”方法,你得确保父类中也有对应的有参数构造方法,不然会编译报错。同样我要提醒一下,当子类构造方法的第一行执行super()无参数方法,那么父类中一定要有无参数构造方法,有的人可能会在父类中写了有参数的构造方法,却忽略了写无参数构造方法,那么在子类构造方法内就会报错,因为当你在一个类中写了有参数的构造方法时,无参数构造方法就会不存在,你需要自己补上无参数的构造方法,这是一个良好的编程习惯。
无论你子类构造方法有没有“this()”和“super()”方法,实例化子类对象一定一定会执行对应的父类构造方法,即不管实例化了一个怎样的孩子,它一定会先实例化一个对应的父亲。
下面给道例题练习一下this()和super()方法:
public class MyTest { public static void main(String[] args) { new Cat(); } } //父类,Animal类 class Animal { //构造函数 public Animal() { super(); System.out.println("1:Animal类的无参数构造函数执行"); } public Animal(int i) { super(); System.out.println("2:Animal类的有int参数构造函数执行"); } } //子类,Cat类 class Cat extends Animal{ //构造函数 public Cat() { this(""); System.out.println("3:Cat类的无参数构造函数执行"); } public Cat(String str) { super(5); System.out.println("4:Cat类的有String参数构造函数执行"); } }
输出结果为:
2:Animal类的有int参数构造函数执行 4:Cat类的有String参数构造函数执行 3:Cat类的无参数构造函数执行
我们又可以得出一个结论:不管你创建什么对象,Object对象的无参数构造方法一定会先执行,因为Object是所有类的根类。
说了这么多,super()到底什么时候使用?再来看下面代码:
public class MyTest { public static void main(String[] args) { Cat c1 = new Cat(3); System.out.println("名字:" + c1.getName()); System.out.println("年龄:" + c1.getAge()); } } //父类,Animal类 class Animal { //私有属性:名字 private String name; //setter and getter public void setName(String name) { this.name = name; } public String getName() { return name; } //构造函数 public Animal() { } public Animal(String name) { this.name = name; } } //子类,Cat类 class Cat extends Animal{ //私有字段:年龄 private int age; //setter and getter public void setAge(int age) { this.age = age; } public int getAge() { return age; } //构造函数 public Cat() { } public Cat(int age) { this.age = age; } }
输出结果:
名字:null 年龄:3
我们也知道,没有给c1对象的name赋值嘛,当然为默认值null啦。
确实如此,所以我们给Cat加一个构造方法,给name和age都赋值。如下:public Cat(String name, int age) { this.name = name; //报错 this.age = age }
显然这样做是会报错的,因为name已经被父类封装成private的了,不能直接访问,可能有的人会这样做:
public Cat(String name, int age) { setName(name); // 因为父类的setName()方法是public的 this.age = age; }
显然这样做的确可以做到给父类的name赋值,但这样做是不建议的,我们在构造方法中通常只调用构造方法,不会去调用实例方法,况且当不止一个变量时,用set方法时,我们就要调用好多个实例方法去完成多个变量的赋值。这时候为什么不考虑使用super()方法呢?如下:
public Cat(String name, int age) { super(name); this.age = age; }
这样就显得文雅,美观多了。
总结:
1、this和super一样,都是对象内部的引用变量,只能出现在对象内部;2、this指向当前对象自己,super指向当前对象的父类型特征,故this的东西比super多,也就是super是this的一部分;
3、this()和super()都只能出现在构造方法的第一行,故this()和super()方法不能共存,当一个类的构造方法第一行中没有this(),也没有super(),系统默认有super()方法;
4、this()是构造方法中调用本类其他的构造方法,super()是当前对象构造方法中去调用自己父类的构造方法。
不知道你现在对 this和super 有没有一个新的认识?嘿嘿。
-
Super Text Mesh 1.6(unity最好的文字渲染插件,支持中文)
2018-04-10 10:33:48SuperTextMesh:能渲染动态文字,富文本支持图文混排,缺点是支持atlas但很弱,资源管理、解析效率内存占用都算不上优秀,有源码可以改 -
apk文件 Superuser(电视直播视频)
2022-06-24 18:48:03apk文件 Superuser(电视直播视频)apk文件 Superuser(电视直播视频)apk文件 Superuser(电视直播视频)apk文件 Superuser(电视直播视频)apk文件 Superuser(电视直播视频)apk文件 Superuser(电视直播视频)... -
superobject1.25
2014-02-18 16:31:26superobject1.25 本人修正superobject1.24的一些问题。 修正D7的一个溢出计算错误, 增加XE2支持。 本人亲测 D7 D2010 XE2 -
Delphi superobject
2014-09-03 09:53:19用于delphi操作JSON的库函数单元,superobject中自动默认为UNICODE编码,处理中文会出现乱码 -
SuperSocket相关dll
2017-12-07 15:54:04log4net.dll 1.2.11.0 SuperSocket.Common.dll SuperSocket.SocketBase.dll SuperSocket.SocketEngine.dll SuperWebSocket.dll -
一起学JAVA 继承 super
2021-05-10 08:49:27this关键字指向调用该方法的对象 一般我们是在当前类中使用this关键字 所以我们常说this代表本类对象的引用 注意:super的使用前提是继承,没有父子类关系,就没有super 注意:this调用构造方法或者super调用构造...1 继承
1.1概念
继承是面向对象最显著的一个特征
继承是从已有的类中派生出新的类,新类能吸收已有类的数据属性和行为,并扩展新的能力.
Java继承是会用已存在的类的定义作为基础建立新类的技术
新类的定义可以增加新的数据或者新的功能,也可以使用父类的功能,但不能选择性的继承父类(超类/基类)
这种继承使得复用以前的代码非常容易,能够大大的缩短开发的周期,降低开发费用.1.2 特点
- 使用extends关键字来表示继承关系
- 相当于子类把父类的功能复制了一份
- Java只支持单继承
- 继承可以传递(爷爷/儿子/孙子这样的关系)
- 父类的私有成员由于私有限制访问,所以子类不能使用父类的私有资源
- 继承多用于功能的修改,子类可以在拥有父类功能的同时,进行功能拓展
- 像是is a的关系
1.3 练习:继承入门案例
创建包: cn.tedu.oop2
创建类: TestExtends.javapackage cn.tedu.oop2; /*本类用于继承的入门案例*/ public class TestExtends { public static void main(String[] args) { //5.分别创建3个类的对象 Animal a = new Animal(); Cat c = new Cat(); MiaoMiao m = new MiaoMiao(); //6.利用对象调用方法进行测试 /*3.继承相当于是子类将父类的功能复制了一份 继承还具有传递性,爷爷的功能会传给爸爸,爸爸的功能会传给孙子*/ a.eat();//爷爷类使用自己的方法 c.eat();//爸爸类可以使用从爷爷类中继承过来的方法 m.eat();//孙子类也可以使用从爷爷类中继承过来的方法 } } /*1.我们通过extends关键字建立子类与父类的继承关系,格式:子类 extends 父类*/ /*2.Java只支持单继承,一个子类只能有一个父类,但是一个父类可以有多个子类*/ //1.创建小动物类--爷爷类 class Animal{ //4.添加爷爷类的普通方法 public void eat(){ System.out.println("小动物Animal吃啥都行~"); } } //2.创建小猫类--爸爸类 /*6.继承是is a的关系,比如小猫是小动物,MiaoMiao是一只小猫 * 继承要求子类必须是父类的一种下属类型,依赖性非常强,强耦合*/ class Cat extends Animal{ //7.定义爸爸类中的属性 int a = 10;//普通属性 private int b = 100;//私有属性 } //3.创建MiaoMiao类--孙子类 class MiaoMiao extends Cat{ /*4.子类可以拥有自己独有的方法,实现了功能的拓展,青出于蓝而胜于蓝*/ //8.定义孙子类的方法 public void studyJava(){ System.out.println("正在学Java"); System.out.println(a); /*5.子类继承了父类以后,可以使用父类的所有非私有资源 * 注意:这个私有资源由于被private修饰,所以没有访问权限*/ //System.out.println(b);//不可以,私有资源被限制访问 } }
2 super
我们可以把super看作是父类的对象:Father super = new Father();
1.当父类的成员变量与子类的变量同名时,使用super指定父类的成员变量
2.使用super在子类构造方法的第一行调用父类构造方法的功能
super();–调用的是父类的无参构造
super(参数);–调用的是父类对应参数的构造方法
注意:在构造方法里,出现的调用位置必须是第一行3 继承的用法
3.1 练习:super之继承中成员变量使用
创建包: cn.tedu.oopextends
创建类: TestExtends1.javapackage cn.tedu.oop2; /*本类用于测试继承中变量的使用*/ public class ExtendsDemo1 { public static void main(String[] args) { //7.创建子类的匿名对象,调用study() new Son().study(); } } //1.创建父类 class Father{ //3.创建父类的成员变量 int sum = 1; int count = 2; } //2.创建子类 class Son extends Father{ //4.创建子类的成员变量 int sum = 10; //5.创建子类的普通方法 public void study(){ System.out.println("goog good study , day day up"); //6.创建子类的局部变量 int sum = 100; //8.打印子类的局部变量sum System.out.println(sum);//100 //9.打印子类的成员变量sum System.out.println(this.sum);//10 //10.打印父类的成员变量sum /*当父类的成员变量与子类的成员变量同名时,可以使用super指定父类的成员变量 * 我们可以把super看作是父类的对象:Father super = new Father();*/ System.out.println(super.sum);//1 System.out.println(count); } }
3.2 练习:super之继承中构造方法的使用
创建包: cn.tedu.oop2
创建类: ExtendsDemo2.javapackage cn.tedu.oop2; /*本类用于测试继承中构造方法的使用 * 1.子类在创建对象时,默认会先调用父类的构造方法 * 2.原因是子类构造函数中的第一行默认存在super();--表示调用父类的无参构造 * 3.当父类没有无参构造时,可以通过super(参数)调用父类的其他含参构造 * 子类必须调用一个父类的构造函数,不管是无参还是含参,选一个即可 * 4.构造方法不可以被继承!因为语法的原因:要求构造方法的名字必须是本类类名 * 不能在子类中出现一个父类名字的构造方法*/ public class ExtendsDemo2 { public static void main(String[] args) { //6.1通过父类的无参构造创建父类对象 //Father2 f = new Father2(); //6.2通过父类的含参构造创建父类对象 //Father2 f2 = new Father2("哈哈哈"); //7.创建子类对象 Son2 s = new Son2(); } } //1.创建父类 class Father2{ //3.创建父类的无参构造 // public Father2(){ // System.out.println("我是父类的无参构造"); // } //4.创建父类的含参构造 public Father2(String s){ System.out.println("我是父类的含参构造"+s); } } //2.创建子类 class Son2 extends Father2{ //5.创建子类的无参构造 public Son2(){ //super();//调用父类的无参构造 super("你好~"); System.out.println("我是子类的无参构造"); } }
4 方法重写Override
- 继承以后,子类就拥有了父类的功能
- 在子类中,可以添加子类特有的功能,也可以修改父类的原有功能
- 子类中方法的签名与父类完全一样时,会发生覆盖/复写的现象
- 注意: 父类的私有方法不能被重写
- 重写的要求:两同两小一大
两同:方法名 参数列表 要完全一致
两小:
子类返回值类型小于等于父类的返回值类型(注意此处说的是继承关系,不是值大小)
子类抛出异常小于等于父类方法抛出异常
一大:子类方法的修饰符权限要大于等于父类被重写方法的修饰符权限
4.1 练习:继承中成员方法的使用
创建包: cn.tedu.oop2
创建类: ExtendsDemo3.javapackage cn.tedu.oop2; /*本类用于测试继承中方法的使用*/ public class ExtendsDemo3 { public static void main(String[] args) { //4.创建对象进行测试 Father f = new Father(); Son s = new Son(); f.eat(); s.eat(); f.play(); s.play(); } } //1.创建父类 class Father{ //3.定义父类中的普通方法 public void eat(){ System.out.println("爸爸爱吃肉"); } public void play(){ System.out.println("爸爸爱放风筝"); } } //2.创建子类 class Son extends Father{ //5.如果子类对父类的方法不满意,可以重写父类的方法 /*重写的原则:两同 两小 一大 * 两同:子类方法的 方法名与参数列表 和父类方法的相同 * 一大:子类方法的 方法修饰符权限 >= 父类方法的 * 两小:子类方法的返回值类型 <= 父类方法的返回值类型 * 注意:这里所说的<=是指子类方法的返回值类型是父类返回值类型的子类 * 或者与父类的返回值类型一致,如果父类方法的返回值类型是void,子类保持一致即可 * */ @Override //注解,用来加在方法上,表示这是一个重写的方法 public void eat(){ System.out.println("儿子爱吃蔬菜"); } @Override public void play(){ System.out.println("儿子爱玩游戏"); } }
5. 拓展
5.1 继承的好处与坏处
继承的好处
提高了代码的复用性(多个类相同的成员可以放在同一个类中)
提高了代码的维护性(如果方法的代码需要修改,只修改一处即可)
继承的坏处
继承让类与类建立了关系,类的耦合性增强
当父类发生变化时,子类实现也不得不跟着变化,削弱了子类的独立性5.1 this与super的区别
this: 代表本类对象的引用
我们可以把this看作是Cat this = new Cat();super:代表父类存储空间的标识,可以理解成父类对象的引用
可以把super看作是Father super = new Father();
this关键字指向调用该方法的对象
一般我们是在当前类中使用this关键字
所以我们常说this代表本类对象的引用注意:super的使用前提是继承,没有父子类关系,就没有super
注意:this调用构造方法或者super调用构造方法,都必须出现在构造方法的第一行
注意:如果父类没有无参构造,需要手动在子类构造方法的第一行调用其他的含参构造
拓展:如果子类重写了父类的方法以后,可以使用super.方法名(参数列表)来调用5.2 重载Overload 与重写Override的区别
重载:在一个类中的现象:同一个类中,存在方法名相同,参数列表不同的方法
重写:是指建立了继承关系以后,子类对父类的方法不满意,可以重写,遵循两同两小一大原则
重载的意义:是为了外界调用方法时方便,不管传入什么样的参数,都可以匹配到对应的同名方法
重写的意义:在不修改源码的情况下,进行功能的修改与拓展(OCP原则:面向修改关闭,面向拓展开放) -
SuperSocket1.6版本文档(中文PDF)
2018-03-21 14:22:14SuperSocket 中文文档,官网上不提供下载,只可看网页,而且最近不知道为什么打不开官网 SuperSocket 中文文档,官网上不提供下载,只可看网页,而且最近不知道为什么打不开官网 -
SuperSocket_WebSocket_WebSocket4Net服务器需要的DLL
2014-05-23 11:32:58基于SuperSocket的服务器 和 客户端程序 所需要的DLL 服务器端<控制台Console程序> (.Net4.0)需要引用 SuperSocket 和 SuperWebSocket -------------------------- 客户端<Unity3D> (.Net3.5) 只需要引用 ... -
SuperSocket示例源码,带客户端和服务器端
2018-07-05 15:16:59这个代码的优点是采用自定义命令行协议以及自定义命令过滤器,执行效率高,可扩展性能强,这都是日常工作敲出来可以正常工作的,欢迎大家下载.有问题请留言! -
Android 动态分区详解(三) 动态分区配置及super.img的生成
2022-04-08 22:51:08本文根据设备是否存在 super 分区,将包含 super 分区的称为原生动态分区,对应于 Android 的默认动态分区配置;将从低版本升级上来不包含 super 分区的称为改造动态分区,对应于 retrofit 的配置。 本文重点介绍 ...1. 导读
关于 Android 的各种特性,永远建议首先参考官方文档,包括两类:
-
一类是代码中自带的文档,包括模块中 README.md, HIDL 和 头文件中的注释等
-
另一类是 Android 官方网站: https://source.android.com/
这里重点说下第二个,现在官方网站上的文档是越来越丰富了。我刚开始分析 A/B 系统的时候,官方文档屈指可数,也没有中文版。现在文档很多,感觉似乎各个模块都有,而且还配有多语言版本,很大程度上可以解决 “my english is poor” 问题。
如果发现有神秘力量导致无法访问官方网站,现在也可以访问无障碍版本: https://source.android.google.cn/
当我真正开始写关于 Android 动态分区配置介绍的时候,又认真看了一遍官方介绍动态分区的页面,只能一声感叹,“卧槽~”。我想说的,官方网站早就说了,以至于我都不知道还能写些什么。
Android 官方介绍动态分区的链接:
《实现动态分区》(https://source.android.com/devices/tech/ota/dynamic_partitions/implement)
官方页面从比较高的角度综述了 Android 动态分区,包括基本原理,配置说明,注意事项等,目的还是给大家介绍如何使用动态分区,重点不在于强调原理。
本文根据设备是否存在 super 分区,将包含 super 分区的称为原生动态分区,对应于 Android 的默认动态分区配置;将从低版本升级上来不包含 super 分区的称为改造动态分区,对应于 retrofit 的配置。
本文重点介绍 Android 动态分区的这编译配置,这些配置是如何生效,super.img 又是如何生成的。
如果您之前没有阅读过上面说的 《实现动态分区》,在开始本文之前,我再建议您先仔细阅读下(官方这篇值得反复阅读),以及本动态分区详解系列的第一篇《Android 动态分区详解(一)》,然后再开始本文。
本文基于 android-10.0.0_r47 代码进行分析
- 如果只想知道原生动态分区需要如何配置,请参考 2.1.1 节;
- 如果只想知道升级改造动态分区需要如何配置,请参考 2.1.2 节;
- 第 2.2 节分析了几个 AOSP 中动态分区配置的示例;
- 第 2.3 节汇总了一些动态分区参数的设置原则;
- 第 3.1 节介绍了原生动态分区和改造动态分区的两组参数最终合二为一;
- 第 3.2 节介绍了动态分区参数最终被输出到
misc_info.txt
文件中用于生成动态分区文件; - 第 4 节介绍了动态分区文件
super.img
或super_empty.img
是如何生成的,解释了我第一篇中 lpmake 为什么会被调用 3 次的疑问。
2. Android 动态分区配置
2.1 动态分区配置选项
根据《实现动态分区》里讲述的,将动态分区需要设置的项列举如下。
2.1.1 原生动态分区配置
对于原生动态分区,需要以下设置:
# 动态分区总开关 PRODUCT_USE_DYNAMIC_PARTITIONS := true # 设置 super 分区大小 BOARD_SUPER_PARTITION_SIZE := <size-in-bytes> # 设置分区组, 可以设置多个组,对于 A/B 设备,每组最终会有 _a 和 _b 两个 slot # 这里以分区组 group_foo 为例,会生成 group_foo_a 和 group_foo_b 两个组 BOARD_SUPER_PARTITION_GROUPS := group_foo # 设置分区组包含的分区, 这里包含 system, vendor 和 product 等 3 个分区 BOARD_GROUP_FOO_PARTITION_LIST := system vendor product # 设置分区组总大小, 总大小需要能够放下分区组里面的所有分区 BOARD_GROUP_FOO_SIZE := <size-in-bytes> # 启用块级重复信息删除,可以进一步压缩 ext4 映像 BOARD_EXT4_SHARE_DUP_BLOCKS := true
2.1.2 改造动态分区配置
对于改造动态分区(retrofit), 需要以下设置:
# 改造(retrofit)动态分区总开关, 这里多了一个 retrofit,标明是升级改造设备 PRODUCT_USE_DYNAMIC_PARTITIONS := true PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true # 设置为所有动态分区内子分区大小的总和 BOARD_SUPER_PARTITION_SIZE := <size-in-bytes> # 设置动态分区子分区, 这里包含 system, vendor 和 product 等 3 个分区 BOARD_SUPER_PARTITION_BLOCK_DEVICES := system vendor product # 逐个设置每一个子分区大小, 这设置 system, vendor 分区大小 # BOARD_SUPER_PARTITION_$(partition)_DEVICE_SIZE BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE := <size-in-bytes> BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE := <size-in-bytes> # 设置分区组, 可以设置多个组,每组最终会有 _a 和 _b 两个 slot BOARD_SUPER_PARTITION_GROUPS := group_foo # 设置分区组包含的分区, 这里包含 system, vendor 和 product 等 3 个分区 BOARD_GROUP_FOO_PARTITION_LIST := system vendor product # 设置分区组总大小, 总大小需要能够放下分区组里面的所有分区 BOARD_GROUP_FOO_SIZE := <size-in-bytes> # 指定 metadata 数据存放的设备,这里设置为 system 分区,也可以是单独的分区 BOARD_SUPER_PARTITION_METADATA_DEVICE := system # 启用块级重复信息删除,可以进一步压缩 ext4 映像 BOARD_EXT4_SHARE_DUP_BLOCKS := true
这里特别说明的是,改造动态分区时,需要通过
BOARD_SUPER_PARTITION_METADATA_DEVICE
指定 metadata 存放的分区。因此,不仅可以将 metadata 数据和某个分区放到一起,例如原生动态分区中就是将 metadata 和 super 分区放到一起;也可以将 metadata 数据单独放到某个分区中,例如 cuttlefish 模拟器中就是将 metadata 单独存放在名为 vda 的分区中 。2.1.3 动态分区配置注意事项
- 在动态分区配置中,不再需要以下分区大小设置了,例如:
BOARD_SYSTEMIMAGE_PARTITION_SIZE := 4294967296 # 4 GB BOARD_VENDORIMAGE_PARTITION_SIZE := 536870912 # 512MB BOARD_PRODUCTIMAGE_PARTITION_SIZE := 1610612736 # 1.5GB
- 原生动态分区中,super 分区内的 system, vendor, product 等需要从 GPT 分区表中移除
- 应避免将 userdata, cache 或任何其他永久性读写分区放在 super 分区中
2.2 动态分区配置示例
关于动态分区配置,这里再以三个 AOSP 自带的 google 设备动态分区配置为例说明,包括原生动态分区和改造动态分区(retrofit),这部分配置位于
device/google
目录之下。2.2.1 crosshatch 设备(Pixel 3 XL)配置示例
crosshatch 设备(Pixel 3 XL) 支持原生动态分区,也支持改造动态分区,配置如下:
# device/google/crosshatch/BoardConfig-common.mk ifneq ($(PRODUCT_USE_DYNAMIC_PARTITIONS), true) # ... else BOARD_EXT4_SHARE_DUP_BLOCKS := true endif ifeq ($(PRODUCT_USE_DYNAMIC_PARTITIONS), true) BOARD_SUPER_PARTITION_GROUPS := google_dynamic_partitions BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST := \ system \ vendor \ product ifeq ($(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS), true) # Normal Pixel 3 must retrofit dynamic partitions. BOARD_SUPER_PARTITION_SIZE := 4072669184 BOARD_SUPER_PARTITION_METADATA_DEVICE := system BOARD_SUPER_PARTITION_BLOCK_DEVICES := system vendor product BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE := 2952790016 BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE := 805306368 BOARD_SUPER_PARTITION_PRODUCT_DEVICE_SIZE := 314572800 # Assume 4MB metadata size. # TODO(b/117997386): Use correct metadata size. BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE := 4069523456 else # Mainline Pixel 3 has an actual super partition. # TODO (b/136154856) product_services partition is removed. # Instead, we will add system_ext once it is ready. # BOARD_PRODUCT_SERVICESIMAGE_FILE_SYSTEM_TYPE := ext4 # TARGET_COPY_OUT_PRODUCT_SERVICES := product_services BOARD_SUPER_PARTITION_SIZE := 12884901888 # Assume 1MB metadata size. # TODO(b/117997386): Use correct metadata size. BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE := 6441402368 # TODO (b/136154856) product_services partition removed. # Instead, we will add system_ext once it is ready. # BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST += \ # product_services \ endif # PRODUCT_RETROFIT_DYNAMIC_PARTITIONS endif # PRODUCT_USE_DYNAMIC_PARTITIONS
crosshatch 动态分区总体上,设备定义了 1 个动态分区组
google_dynamic_partitions
, 包含分区system vendor product
。对于原生动态分区,有:
# 启用块级重复信息删除,可以进一步压缩 ext4 映像 BOARD_EXT4_SHARE_DUP_BLOCKS := true # 总开关 PRODUCT_USE_DYNAMIC_PARTITIONS := true # 分区组和子分区 BOARD_SUPER_PARTITION_GROUPS := google_dynamic_partitions BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor product # super 分区和分区组大小 BOARD_SUPER_PARTITION_SIZE := 12884901888 BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE := 6441402368
对于改造动态分区,有:
# 启用块级重复信息删除,可以进一步压缩 ext4 映像 BOARD_EXT4_SHARE_DUP_BLOCKS := true # 总开关 PRODUCT_USE_DYNAMIC_PARTITIONS := true PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true # 分区组和子分区 BOARD_SUPER_PARTITION_GROUPS := google_dynamic_partitions BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor product # super 分区大小 BOARD_SUPER_PARTITION_SIZE := 4072669184 # metadata 存放的设备 BOARD_SUPER_PARTITION_METADATA_DEVICE := system # 动态分区内的子分区 BOARD_SUPER_PARTITION_BLOCK_DEVICES := system vendor product # 每个子分区大小 BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE := 2952790016 # 2816M BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE := 805306368 # 768M BOARD_SUPER_PARTITION_PRODUCT_DEVICE_SIZE := 314572800 # 300M # 分区组大小 BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE := 4069523456
2.2.2 bonito 设备(Pixel 3a XL)配置示例
bonito 设备(Pixel 3a XL)只支持改造动态分区,配置如下:
# device/google/bonito/device-common.mk # Enable retrofit dynamic partitions for all bonito # and sargo targets PRODUCT_USE_DYNAMIC_PARTITIONS := true PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true # device/google/bonito/BoardConfig-common.mk BOARD_EXT4_SHARE_DUP_BLOCKS := true BOARD_SUPER_PARTITION_GROUPS := google_dynamic_partitions BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST := \ system \ vendor \ product BOARD_SUPER_PARTITION_SIZE := 4072669184 BOARD_SUPER_PARTITION_METADATA_DEVICE := system BOARD_SUPER_PARTITION_BLOCK_DEVICES := system vendor BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE := 3267362816 BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE := 805306368 # Assume 4MB metadata size. # TODO(b/117997386): Use correct metadata size. BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE := 4068474880
从这里的配置看,和 crosshatch 设备(Pixel 3 XL)对改造动态分区的配置是一样的,只是少了一个 product 分区。
2.2.3 模拟器 cuttlefish 配置示例
模拟器 cuttlefish 的动态分区配置位于文件:
device/google/cuttlefish/shared/BoardConfig.mk
,如下:# device/google/cuttlefish/shared/BoardConfig.mk ifeq ($(TARGET_USE_DYNAMIC_PARTITIONS),true) BOARD_SUPER_PARTITION_SIZE := 6442450944 BOARD_SUPER_PARTITION_GROUPS := google_dynamic_partitions BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor product BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE := 6442450944 BOARD_SUPER_PARTITION_METADATA_DEVICE := vda BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT := true BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE := true TARGET_RELEASETOOLS_EXTENSIONS := device/google/cuttlefish/shared else # ... endif
这里是模拟 cuttlefish 原生动态分区的配置,重点如下:
- 不带
PRODUCT_RETROFIT_DYNAMIC_PARTITIONS
, 原生动态分区 - super 分区大小为 6442450944
- 定义了一个动态分区组
google_dynamic_partitions
, 大小为 6442450944, 包含三个子分区system vendor product
- 指定了 metadata 数据存放的分区 vda
另外:
BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT := true
指定了 super.img 由$(PRODUCT_OUT)
目录下的文件创建,并输出到$(PRODUCT_OUT)/super.img
中
注意: 上面的 cuttlefish 的例子中,
- 使用自定义的
TARGET_USE_DYNAMIC_PARTITIONS
作为开关,而不是PRODUCT_USE_DYNAMIC_PARTITIONS
, 不过后者会根据前者设置为 true BOARD_SUPER_PARTITION_SIZE
和BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE
一样,都是 6442450944,所以 cuttlefish 模拟器应该不是 A/B 设备。A/B 设备下要求动态分区组大小为:(super 分区大小 - 开销) / 2
2.3 动态分区参数检查
设置了动态分区参数以后,Android 在编译时会对参数进行检查,检查的内容包括两类:
-
开关参数检查,检查动态分区的配置开关是否冲突
-
分区大小参数的检查,检查分区大小设置是否符合要求
我本来对这几段 Makefile 代码做了注释,但因为很长,贴上的话整篇文章就更啰嗦了,所以这里直接贴上结论把。
2.3.1 开关参数检查
文件
build/make/core/config.mk
的 811~878 行,对动态分区的开关参数进行检查。参考链接: http://aospxref.com/android-10.0.0_r47/xref/build/make/core/config.mk#811
这段代码检查的重点有:
-
改造动态分区开关和动态分区总开关必须同时设置
# 总开关 PRODUCT_USE_DYNAMIC_PARTITIONS := true # 改造(retrofit)动态分区开关 PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true
-
打开了动态分区之后,列表(system, vendor, odm, product, product_services)对应分区的以下 SIZE 配置不能同时设置
# (system, vendor, odm, product, product_services) BOARD_$(device)IMAGE_PARTITION_SIZE BOARD_$(device)IMAGE_PARTITION_RESERVED_SIZE
-
对每一个分组 group,需要同时设置
PARTITION_LIST
和SIZE
参数BOARD_$(group)_PARTITION_LIST BOARD_$(group)_SIZE
-
如果分组没有设置
BOARD_$(group)_PARTITION_LIST
, 则默认分组内没有分区 -
分组名
BOARD_SUPER_PARTITION_GROUPS
不能设置为列表(system vendor product product_services odm)中的名字 -
打开动态分区后,不需要再设置
BOARD_BUILD_SYSTEM_ROOT_IMAGE = true
2.3.2 分区大小限制
文件
build/make/core/Makefile
的 3375~3485 行,定义了多个宏对动态分区以及子分区的大小进行检查。参考链接: http://aospxref.com/android-10.0.0_r47/xref/build/make/core/Makefile#3375
详细的代码比较繁琐,主要是各分区或分组大小数值的计算和比较。
这里原文引用一下《实现动态分区》中说的动态分区大小限制:
- 对于虚拟 A/B 启动设备,所有组的最大大小总和不得超过:
BOARD_SUPER_PARTITION_SIZE
- 开销 - 对于 A/B 启动设备,所有组的最大大小总和必须为:
BOARD_SUPER_PARTITION_SIZE
/ 2 - 开销 - 对于非 A/B 设备和改造的 A/B 设备,所有组的大小上限总和必须为:
BOARD_SUPER_PARTITION_SIZE
- 开销 - 在构建时,更新组中每个分区的映像大小总和不得超过组的大小上限。
- 在计算时需要扣除开销,因为要考虑元数据、对齐等。合理的开销是 4 MiB,但您可以根据设备的需要选择更大的开销。
这里说下上面提到的 4M 总开销的来源,主要有两类:
- 元数据(metadata)开销,元数据位于分区开始的 4KB~1MB 范围内
- 分区对齐开销,默认分区按照 1MB 对齐
如果动态分区中定义了一个分区组,包含三个分区(system, vendor, product),对于 A/B 系统,分区组会有两个槽位,因此一共有 6 个子分区。按中值计算,平均每个子分区对齐开销为 0.5M,这样 6 个分区对齐,一共需要 0.5M x 6 = 3M 的总对齐开销。再加上元数据(metadata) 1M 的开销,所以预估
4M = 1M + 0.5M x 6
的总开销是合理的。3. Android 动态分区参数的处理
3.1 原生和改造动态分区两套参数的合并
前面第 2 节提到,对于原生动态分区和改造动态分区,需要进行不同的参数设置。
文件
build/make/core/config.mk
的 923~994行,代码将原生动态分区和改造动态分区的两组参数合并成一组参数进行了处理。参考链接: http://aospxref.com/android-10.0.0_r47/xref/build/make/core/config.mk#923
以
2.2.1 crosshatch 设备(Pixel 3 XL)配置示例
节提到的原生动态分区和改造动态分区参数为例,经过处理,最终得到以下的动态分区参数。对于原生动态分区为:
PRODUCT_USE_DYNAMIC_PARTITIONS := true BOARD_EXT4_SHARE_DUP_BLOCKS := true BOARD_SUPER_PARTITION_SIZE := 4072669184 BOARD_SUPER_PARTITION_METADATA_DEVICE := super BOARD_SUPER_PARTITION_BLOCK_DEVICES := super BOARD_SUPER_PARTITION_SUPER_DEVICE_SIZE := 4072669184 BOARD_SUPER_PARTITION_GROUPS := google_dynamic_partitions BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor product BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE := 4069523456 BOARD_BUILD_RETROFIT_DYNAMIC_PARTITIONS_OTA_PACKAGE := INTERNAL_KERNEL_CMDLINE += \ androidboot.super_partition=$(BOARD_SUPER_PARTITION_METADATA_DEVICE)
对于改造动态分区为:
PRODUCT_USE_DYNAMIC_PARTITIONS := true PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true BOARD_EXT4_SHARE_DUP_BLOCKS := true BOARD_SUPER_PARTITION_SIZE := 4072669184 BOARD_SUPER_PARTITION_METADATA_DEVICE := system BOARD_SUPER_PARTITION_BLOCK_DEVICES := system vendor product BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE := 2952790016 BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE := 805306368 BOARD_SUPER_PARTITION_PRODUCT_DEVICE_SIZE := 314572800 BOARD_SUPER_PARTITION_GROUPS := google_dynamic_partitions BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor product BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE := 4069523456 BOARD_BUILD_RETROFIT_DYNAMIC_PARTITIONS_OTA_PACKAGE := true INTERNAL_KERNEL_CMDLINE += \ androidboot.super_partition=$(BOARD_SUPER_PARTITION_METADATA_DEVICE)
在这里,这两套参数最终合并成了一套参数。
3.2 动态分区参数最终去了哪里?
上一节提到原生动态分区和改造动态分区的不同设置最终会合并成对同一组参数的设置。
那转换成这同一组参数后,后续是如何处理的呢?
在
build/make/core/Makefile
中定义了一个宏函数dump-dynamic-partitions-info
,用于将原生动态分区相关信息输出到指定的文件中,如下:# $(1): file define dump-dynamic-partitions-info $(if $(filter true,$(PRODUCT_USE_DYNAMIC_PARTITIONS)), \ echo "use_dynamic_partitions=true" >> $(1)) $(if $(filter true,$(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS)), \ echo "dynamic_partition_retrofit=true" >> $(1)) echo "lpmake=$(notdir $(LPMAKE))" >> $(1) $(if $(filter true,$(PRODUCT_BUILD_SUPER_PARTITION)), $(if $(BOARD_SUPER_PARTITION_SIZE), \ echo "build_super_partition=true" >> $(1))) $(if $(filter true,$(BOARD_BUILD_RETROFIT_DYNAMIC_PARTITIONS_OTA_PACKAGE)), \ echo "build_retrofit_dynamic_partitions_ota_package=true" >> $(1)) echo "super_metadata_device=$(BOARD_SUPER_PARTITION_METADATA_DEVICE)" >> $(1) $(if $(BOARD_SUPER_PARTITION_BLOCK_DEVICES), \ echo "super_block_devices=$(BOARD_SUPER_PARTITION_BLOCK_DEVICES)" >> $(1)) $(foreach device,$(BOARD_SUPER_PARTITION_BLOCK_DEVICES), \ echo "super_$(device)_device_size=$(BOARD_SUPER_PARTITION_$(call to-upper,$(device))_DEVICE_SIZE)" >> $(1);) $(if $(BOARD_SUPER_PARTITION_PARTITION_LIST), \ echo "dynamic_partition_list=$(BOARD_SUPER_PARTITION_PARTITION_LIST)" >> $(1)) $(if $(BOARD_SUPER_PARTITION_GROUPS), echo "super_partition_groups=$(BOARD_SUPER_PARTITION_GROUPS)" >> $(1)) $(foreach group,$(BOARD_SUPER_PARTITION_GROUPS), \ echo "super_$(group)_group_size=$(BOARD_$(call to-upper,$(group))_SIZE)" >> $(1); \ $(if $(BOARD_$(call to-upper,$(group))_PARTITION_LIST), \ echo "super_$(group)_partition_list=$(BOARD_$(call to-upper,$(group))_PARTITION_LIST)" >> $(1);)) $(if $(filter true,$(TARGET_USERIMAGES_SPARSE_EXT_DISABLED)), \ echo "build_non_sparse_super_partition=true" >> $(1)) $(if $(filter true,$(BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE)), \ echo "super_image_in_update_package=true" >> $(1)) endef
调用
dump-dynamic-partitions-info
主要有以下 3 个地方:- 生成
BUILT_TARGET_FILES_PACKAGE
目标时,将动态分区信息追加到$(zip_root)/META/misc_info.txt
文件中 - 被宏
dump-super-image-info
内部调用,在编译 super.img 或 super_empty.img 时,将动态分区信息输出到各自对应的misc_info.txt
中
例如,下面是一个 Broadcom 某平台上 super.img 的
misc_info.txt
内容:$ cat out/target/product/inuvik/obj/PACKAGING/superimage_debug_intermediates/misc_info.txt use_dynamic_partitions=true lpmake=lpmake build_super_partition=true super_metadata_device=super super_block_devices=super super_super_device_size=3028287488 dynamic_partition_list= system vendor super_partition_groups=bcm_ref super_bcm_ref_group_size=1509949440 super_bcm_ref_partition_list=system vendor ab_update=true system_image=out/target/product/inuvik/system.img vendor_image=out/target/product/inuvik/vendor.img
下面是谷歌 crosshatch 设备
super_empty.img
文件misc_info.txt
的内容:$ cat out/target/product/crosshatch/obj/PACKAGING/super_empty_intermediates/misc_info.txt use_dynamic_partitions=true dynamic_partition_retrofit=true lpmake=lpmake build_super_partition=true build_retrofit_dynamic_partitions_ota_package=true super_metadata_device=system super_block_devices=system vendor product super_system_device_size=2952790016 super_vendor_device_size=805306368 super_product_device_size=314572800 dynamic_partition_list= system vendor product super_partition_groups=google_dynamic_partitions super_google_dynamic_partitions_group_size=4069523456 super_google_dynamic_partitions_partition_list=system vendor product ab_update=true
至于动态分区参数输出到
misc_info.txt
文件中以后,会怎么处理,将在 super.img 文件如何生成的一节展开。4. 原生动态分区 super.img 的生成
还记得我在《Android 动态分区详解(一)》中提到,在 make 的 log 中搜索 lpmake 时发现有 3 个地方调用 lpmake 吗?
仔细阅读
build/make/core/Makefile
,就会发现有两个地方去生成super.img
, 一个地方生成super_empty.img
, 在生成这些文件时通过脚本build_super_image.py
调用 lpmake 去生成 metadata,所以总共调用了 3 次。所幸的是,这三个地方都有注释,比较好找,分别是:
-
目标:
superimage_dist
,注释:super partition image (dist)
代码: http://aospxref.com/android-10.0.0_r47/xref/build/make/core/Makefile#4423
-
目标:
superimage
, 注释:super partition image for development
代码: http://aospxref.com/android-10.0.0_r47/xref/build/make/core/Makefile#4460
-
目标:
superimage_empty
, 注释:super empty image
代码: http://aospxref.com/android-10.0.0_r47/xref/build/make/core/Makefile#4514
4.1 dist 模式的 super.img
dist 模式下基于
target_files
(例如:inuvik-target_files-eng.rg935739.zip
) 的内容生成 super.img,其生成的文件位于:out/target/product/inuvik/obj/PACKAGING/super.img_intermediates/super.img
主要由 superimage_dist 目标构成依赖关系路径:
dist --> dist_files --> superimage_dist --> super.img
源码如下:
# ----------------------------------------------------------------- # super partition image (dist) ifeq (true,$(PRODUCT_BUILD_SUPER_PARTITION)) # BOARD_SUPER_PARTITION_SIZE must be defined to build super image. ifneq ($(BOARD_SUPER_PARTITION_SIZE),) # Dump variables used by build_super_image.py. define dump-super-image-info $(call dump-dynamic-partitions-info,$(1)) $(if $(filter true,$(AB_OTA_UPDATER)), \ echo "ab_update=true" >> $(1)) endef ifneq (true,$(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS)) # For real devices and for dist builds, build super image from target files to an intermediate directory. INTERNAL_SUPERIMAGE_DIST_TARGET := $(call intermediates-dir-for,PACKAGING,super.img)/super.img $(INTERNAL_SUPERIMAGE_DIST_TARGET): extracted_input_target_files := $(patsubst %.zip,%,$(BUILT_TARGET_FILES_PACKAGE)) $(INTERNAL_SUPERIMAGE_DIST_TARGET): $(LPMAKE) $(BUILT_TARGET_FILES_PACKAGE) $(BUILD_SUPER_IMAGE) $(call pretty,"Target super fs image from target files: $@") PATH=$(dir $(LPMAKE)):$$PATH \ $(BUILD_SUPER_IMAGE) -v $(extracted_input_target_files) $@ # Skip packing it in dist package because it is in update package. ifneq (true,$(BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE)) $(call dist-for-goals,dist_files,$(INTERNAL_SUPERIMAGE_DIST_TARGET)) endif .PHONY: superimage_dist superimage_dist: $(INTERNAL_SUPERIMAGE_DIST_TARGET) endif # PRODUCT_RETROFIT_DYNAMIC_PARTITIONS != "true" endif # BOARD_SUPER_PARTITION_SIZE != "" endif # PRODUCT_BUILD_SUPER_PARTITION == "true"
4.2 debug 模式的 super.img
dist 模式下基于
misc_info.txt
的内容生成 super.img,其生成的文件位于:out/target/product/inuvik/super.img
主要由 superimage 目标构成依赖关系路径:
droid --> droidcore --> superimage --> super.img
示例
misc_info.txt
如下:# misc_info.txt $ cat out/target/product/inuvik/obj/PACKAGING/superimage_debug_intermediates/misc_info.txt use_dynamic_partitions=true lpmake=lpmake build_super_partition=true super_metadata_device=super super_block_devices=super super_super_device_size=3028287488 dynamic_partition_list= system vendor super_partition_groups=bcm_ref super_bcm_ref_group_size=1509949440 super_bcm_ref_partition_list=system vendor ab_update=true system_image=out/target/product/inuvik/system.img vendor_image=out/target/product/inuvik/vendor.img
这里说成是 debug 模式是不准确的,主要是说想对于 release 而言,这里编译出来的镜像是开发时使用的,而通过
make dist
得到的镜像,是 release 使用的。生成
super.img
的源码如下:# ----------------------------------------------------------------- # super partition image for development ifeq (true,$(PRODUCT_BUILD_SUPER_PARTITION)) ifneq ($(BOARD_SUPER_PARTITION_SIZE),) ifneq (true,$(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS)) # Build super.img by using $(INSTALLED_*IMAGE_TARGET) to $(1) # $(1): built image path # $(2): misc_info.txt path; its contents should match expectation of build_super_image.py define build-superimage-target mkdir -p $(dir $(2)) rm -rf $(2) $(call dump-super-image-info,$(2)) $(foreach p,$(BOARD_SUPER_PARTITION_PARTITION_LIST), \ echo "$(p)_image=$(INSTALLED_$(call to-upper,$(p))IMAGE_TARGET)" >> $(2);) mkdir -p $(dir $(1)) PATH=$(dir $(LPMAKE)):$$PATH \ $(BUILD_SUPER_IMAGE) -v $(2) $(1) endef # out/target/product/inuvik/super.img INSTALLED_SUPERIMAGE_TARGET := $(PRODUCT_OUT)/super.img INSTALLED_SUPERIMAGE_DEPENDENCIES := $(LPMAKE) $(BUILD_SUPER_IMAGE) \ $(foreach p, $(BOARD_SUPER_PARTITION_PARTITION_LIST), $(INSTALLED_$(call to-upper,$(p))IMAGE_TARGET)) # If BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT is set, super.img is built from images in the # $(PRODUCT_OUT) directory, and is built to $(PRODUCT_OUT)/super.img. Also, it will # be built for non-dist builds. This is useful for devices that uses super.img directly, e.g. # virtual devices. ifeq (true,$(BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT)) $(INSTALLED_SUPERIMAGE_TARGET): $(INSTALLED_SUPERIMAGE_DEPENDENCIES) $(call pretty,"Target super fs image for debug: $@") $(call build-superimage-target,$(INSTALLED_SUPERIMAGE_TARGET),\ $(call intermediates-dir-for,PACKAGING,superimage_debug)/misc_info.txt) droidcore: $(INSTALLED_SUPERIMAGE_TARGET) # For devices that uses super image directly, the superimage target points to the file in $(PRODUCT_OUT). .PHONY: superimage superimage: $(INSTALLED_SUPERIMAGE_TARGET) endif # BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT # Build $(PRODUCT_OUT)/super.img without dependencies. .PHONY: superimage-nodeps supernod superimage-nodeps supernod: intermediates := superimage-nodeps supernod: | $(INSTALLED_SUPERIMAGE_DEPENDENCIES) $(call pretty,"make $(INSTALLED_SUPERIMAGE_TARGET): ignoring dependencies") $(call build-superimage-target,$(INSTALLED_SUPERIMAGE_TARGET),\ $(call intermediates-dir-for,PACKAGING,superimage-nodeps)/misc_info.txt) endif # PRODUCT_RETROFIT_DYNAMIC_PARTITIONS != "true" endif # BOARD_SUPER_PARTITION_SIZE != "" endif # PRODUCT_BUILD_SUPER_PARTITION == "true"
4.3 super_empty.img
基于
misc_info.txt
文件生成的 super_empty.img,其生成的文件位于:out/target/product/inuvik/super_empty.img
主要通过
main.mk
中的 superimage_empty 目标形成依赖关系路径:dist --> dist_files --> superimage_dist --> super_empty.img
生成
super_empty.img
的源码如下:# ----------------------------------------------------------------- # super empty image ifeq (true,$(PRODUCT_BUILD_SUPER_PARTITION)) ifneq ($(BOARD_SUPER_PARTITION_SIZE),) INSTALLED_SUPERIMAGE_EMPTY_TARGET := $(PRODUCT_OUT)/super_empty.img $(INSTALLED_SUPERIMAGE_EMPTY_TARGET): intermediates := $(call intermediates-dir-for,PACKAGING,super_empty) $(INSTALLED_SUPERIMAGE_EMPTY_TARGET): $(LPMAKE) $(BUILD_SUPER_IMAGE) $(call pretty,"Target empty super fs image: $@") mkdir -p $(intermediates) rm -rf $(intermediates)/misc_info.txt $(call dump-super-image-info,$(intermediates)/misc_info.txt) PATH=$(dir $(LPMAKE)):$$PATH \ $(BUILD_SUPER_IMAGE) -v $(intermediates)/misc_info.txt $@ $(call dist-for-goals,dist_files,$(INSTALLED_SUPERIMAGE_EMPTY_TARGET)) endif # BOARD_SUPER_PARTITION_SIZE != "" endif # PRODUCT_BUILD_SUPER_PARTITION == "true"
4.4
build_super_image.py
脚本仔细观察上面生成
super.img
或super_empty.img
的代码,分别通过以下的命令实现:-
dist 模式的 super.img
$(call pretty,"Target super fs image from target files: $@") PATH=$(dir $(LPMAKE)):$$PATH \ $(BUILD_SUPER_IMAGE) -v $(extracted_input_target_files) $@
-
debug 模式的 super.img
# Build super.img by using $(INSTALLED_*IMAGE_TARGET) to $(1) # $(1): built image path # $(2): misc_info.txt path; its contents should match expectation of build_super_image.py define build-superimage-target mkdir -p $(dir $(2)) rm -rf $(2) $(call dump-super-image-info,$(2)) $(foreach p,$(BOARD_SUPER_PARTITION_PARTITION_LIST), \ echo "$(p)_image=$(INSTALLED_$(call to-upper,$(p))IMAGE_TARGET)" >> $(2);) mkdir -p $(dir $(1)) PATH=$(dir $(LPMAKE)):$$PATH \ $(BUILD_SUPER_IMAGE) -v $(2) $(1) endef $(call pretty,"Target super fs image for debug: $@") $(call build-superimage-target,$(INSTALLED_SUPERIMAGE_TARGET),\ $(call intermediates-dir-for,PACKAGING,superimage_debug)/misc_info.txt)
-
super_empty.img
$(call pretty,"Target empty super fs image: $@") mkdir -p $(intermediates) rm -rf $(intermediates)/misc_info.txt $(call dump-super-image-info,$(intermediates)/misc_info.txt) PATH=$(dir $(LPMAKE)):$$PATH \ $(BUILD_SUPER_IMAGE) -v $(intermediates)/misc_info.txt $@
其中,在
build/make/core/config.mk
中设置BUILD_SUPER_IMAGE
:BUILD_SUPER_IMAGE := build/make/tools/releasetools/build_super_image.py
总体说来,脚本
build_super_image.py
接收两个参数,第一个是输入文件或目录,第二个是输出 super.img 的路径。对于第一个参数,有三种情况:
- 如果输入是
misc_info.txt
文件路径,则直接提取其中动态分区相关内容,传递给 lpmake 工具生成动态分区文件 - 如果输入是目录,则查找其目录下的
META/misc_info.txt
文件,提取动态分区配置传递给 lpmake - 如果输入是 zip 文件,则先解压缩打临时目录总,再按照目录的情况进行处理
归根到底,
build_super_image.py
会查找misc_info.txt
文件(如果是目录,就查找目录下的文件;如果是 zip 文件,就解压缩后提取文件),并把其中动态分区参数传递给 lpmake 用来生成动态分区文件super.img
。如果动态分区中,某个分区还带有镜像文件的路径,就会将镜像文件放到
super.img
中;如果分区没有相应的文件,则最终的super.img
就不会包含该分区的 image 内容。默认编译生成的
super.img
只包含了slot a
的镜像,另外一个slot b
为空。可以使用 lpdump 分析 metadata,或者使用 lpunpack 解包查看。5. 总结
动态分区参数有两类设置,一类是原生动态分区配置,一类是改造动态分区配置。具体需要设置的参数请查看本文 2.1 节。
动态分区虽然有两套参数,但最终这两套参数会合二为一成为同一套参数,并将这些参数设置输出到
misc_info.txt
中。两套参数的处理细节请参考本文的第 3 节。编译系统调用
build_super_image.py
脚本读取misc_info.txt
中的动态分区配置参数,传递给 lpmake 工具。lpmake 根据动态分区参数中各分区的大小以及 image 路径,生成最终的 super.img(包括 metadata 和各分区 image)。默认生成的
super.img
只包含了slot a
的镜像,另外一个slot b
为空,可以使用 lpdump 分析 metadata,或者使用 lpunpack 解包查看。关于改造动态分区的 image 如何生成,值得另外开篇详细说明。
6. 其它
洛奇工作中常常会遇到自己不熟悉的问题,这些问题可能并不难,但因为不了解,找不到人帮忙而瞎折腾,往往导致浪费几天甚至更久的时间。
所以我组建了几个微信讨论群(记得微信我说加哪个群,如何加微信见后面),欢迎一起讨论:
- 一个密码编码学讨论组,主要讨论各种加解密,签名校验等算法,请说明加密码学讨论群。
- 一个Android OTA的讨论组,请说明加Android OTA群。
- 一个git和repo的讨论组,请说明加git和repo群。
在工作之余,洛奇尽量写一些对大家有用的东西,如果洛奇的这篇文章让您有所收获,解决了您一直以来未能解决的问题,不妨赞赏一下洛奇,这也是对洛奇付出的最大鼓励。扫下面的二维码赞赏洛奇,金额随意:
洛奇自己维护了一个公众号“洛奇看世界”,一个很佛系的公众号,不定期瞎逼逼。公号也提供个人联系方式,一些资源,说不定会有意外的收获,详细内容见公号提示。扫下方二维码关注公众号:
-
-
android10 super.img编译
2020-06-01 17:32:00文章目录`make superiamge``INSTALLED_SUPERIMAGE_TARGET`牛逼哄哄的`droidcore`就依赖于它规则再来看看它的依赖`INSTALLED_SUPERIMAGE_DEPENDENCIES``make superimage-nodeps` or `make supernod`规则命令`...