super 订阅
刘超是唱歌、创作、舞台表演全能艺人。2005踏上学习音乐的追梦之旅,2010快乐男声网络直通区20强选手。 展开全文
刘超是唱歌、创作、舞台表演全能艺人。2005踏上学习音乐的追梦之旅,2010快乐男声网络直通区20强选手。
信息
国    籍
中国
出生地
湖北
现    居
北京
代表作品
梦开始的地方
体    重
56公斤
学    校
现就读于北京演艺学院
出生日期
01月01日
性    格
活泼,耍酷
中文名
刘超
民    族
专    业
音乐制作,流行演唱
身    高
173公分
性    别
外文名
super
星    座
摩羯座
文化程度
本科
sqoop特征
收起全文
精华内容
下载资源
问答
  • 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)
    
    更多相关内容
  • Delphi读写操作JSON字符串时,需引用一个superobject.pas文件。 var jo,jt:ISuperObject; begin jo:=SO(); jt:=SO(); jo.S['姓名']:='小王'; jo.I['年龄']:=25; jo.S['性别']:='男'; jt.O['人员']:=jo; ...
  • Delphi superobject 支持XE10.3 json
  • superobject1.26

    2018-05-28 16:55:50
    superobject1.26 SuperObject.pas,superxmlparser.pas
  • supersocket1.6.6源代码学习。生成的类库有SuperSocket.Common.dll、SuperSocket.SocketBase.dll、SuperSocket.SocketEngine.dll、log4net.dll
  • superobject 1.25

    2017-05-02 17:04:30
    superobject 1.25 ------------------ SuperObject提供了两个类库文件SuperObject.pas,superxmlparser.pas,其中SuperObject.pas就是用于操作json数据,而superxmlparser.pas用与从XML数据中解析出json数据。
  • SuperSU-v2.79.zip

    2018-05-03 14:01:00
    android root工具 supersu-v2.79版本。超级授权管理专业工具,它是款对Android手机进行ROOT的超级权限管理工具,超级用户访问权限管理必备利器。Super SU 原生无广告,自带简体中文,支持已ROOT设备上所有应用的超级...
  • SuperSocket-master_Socket 、Socket、SuperSocket、TCP、UDP
  • 点云配准Super-4PCS

    2018-11-15 11:23:53
    点云配准算法super-4pcs,是4pcs算法的升级版,代码来自于官网。
  • SuperSocket客户端+服务端完整Demo 代码,包括 net4.0运行库,比较适合新手!
  • socket服务端采用SuperSocket搭建,客户端与服务端进行连接及向服务端发送消息,服务端使用业务向客户端发送消息进行通信
  • SuperSocket(服务端winform+客户端winform) 案例,可直接运行跑起来
  • SuperSocket实例程序

    2018-03-20 22:29:46
    基于SuperSocket V1.6.1开发的示例程序,含服务端和客户端,编译无报错,运行正常。学习基于SuperSocket开发的同学值得一看
  • 解压后有一个apk 是安装包,另一个zip则是SuperSU的卡刷包,发现SuperSU的官网已经不再可以访问了,所以就上传到CSDN去
  • superObject支持xe10,一直用这个习惯了,xe版本带的用的有问题
  • Json是一种轻量级数据传输格式,广泛应用互联网和各应用中,json主要采用键值对来表示数据项,多个数据项之间用逗号分隔,也可以...下面注重介绍一下在delphi中使用json,在delphi中使用json常用superobject单元文件
  • SuperSU-v2.79安装包

    2018-05-24 18:38:40
    supersu安装,用于管理root权限,v2.79版本。 .
  • super_decision操作方法(中文版、英文版、图文版)
  • Java中super关键字及super()的使用

    万次阅读 多人点赞 2020-07-06 22:52:15
    super关键字的使用: (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 有没有一个新的认识?嘿嘿。

    展开全文
  • SuperTextMesh:能渲染动态文字,富文本支持图文混排,缺点是支持atlas但很弱,资源管理、解析效率内存占用都算不上优秀,有源码可以改
  • apk文件 Superuser(电视直播视频)apk文件 Superuser(电视直播视频)apk文件 Superuser(电视直播视频)apk文件 Superuser(电视直播视频)apk文件 Superuser(电视直播视频)apk文件 Superuser(电视直播视频)...
  • superobject1.25

    热门讨论 2014-02-18 16:31:26
    superobject1.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:04
    log4net.dll 1.2.11.0 SuperSocket.Common.dll SuperSocket.SocketBase.dll SuperSocket.SocketEngine.dll SuperWebSocket.dll
  • 一起学JAVA 继承 super

    万次阅读 多人点赞 2021-05-10 08:49:27
    this关键字指向调用该方法的对象 一般我们是在当前类中使用this关键字 所以我们常说this代表本类对象的引用 注意:super的使用前提是继承,没有父子类关系,就没有super 注意:this调用构造方法或者super调用构造...

    1 继承

    1.1概念

    继承是面向对象最显著的一个特征
    继承是从已有的类中派生出新的类,新类能吸收已有类的数据属性和行为,并扩展新的能力.
    Java继承是会用已存在的类的定义作为基础建立新类的技术
    新类的定义可以增加新的数据或者新的功能,也可以使用父类的功能,但不能选择性的继承父类(超类/基类)
    这种继承使得复用以前的代码非常容易,能够大大的缩短开发的周期,降低开发费用.

    1.2 特点

    1. 使用extends关键字来表示继承关系
    2. 相当于子类把父类的功能复制了一份
    3. Java只支持单继承
    4. 继承可以传递(爷爷/儿子/孙子这样的关系)
    5. 父类的私有成员由于私有限制访问,所以子类不能使用父类的私有资源
    6. 继承多用于功能的修改,子类可以在拥有父类功能的同时,进行功能拓展
    7. 像是is a的关系

    1.3 练习:继承入门案例

    创建包: cn.tedu.oop2
    创建类: TestExtends.java

    package 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.java

    package 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.java

    package 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

    1. 继承以后,子类就拥有了父类的功能
    2. 在子类中,可以添加子类特有的功能,也可以修改父类的原有功能
    3. 子类中方法的签名与父类完全一样时,会发生覆盖/复写的现象
    4. 注意: 父类的私有方法不能被重写
    5. 重写的要求:两同两小一大
      两同:方法名 参数列表 要完全一致
      两小:
      子类返回值类型小于等于父类的返回值类型(注意此处说的是继承关系,不是值大小)
      子类抛出异常小于等于父类方法抛出异常
      一大:子类方法的修饰符权限要大于等于父类被重写方法的修饰符权限

    4.1 练习:继承中成员方法的使用

    创建包: cn.tedu.oop2
    创建类: ExtendsDemo3.java

    package 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原则:面向修改关闭,面向拓展开放)

    展开全文
  • SuperSocket 中文文档,官网上不提供下载,只可看网页,而且最近不知道为什么打不开官网 SuperSocket 中文文档,官网上不提供下载,只可看网页,而且最近不知道为什么打不开官网
  • 基于SuperSocket的服务器 和 客户端程序 所需要的DLL 服务器端<控制台Console程序> (.Net4.0)需要引用 SuperSocket 和 SuperWebSocket -------------------------- 客户端<Unity3D> (.Net3.5) 只需要引用 ...
  • 这个代码的优点是采用自定义命令行协议以及自定义命令过滤器,执行效率高,可扩展性能强,这都是日常工作敲出来可以正常工作的,欢迎大家下载.有问题请留言!
  • 本文根据设备是否存在 super 分区,将包含 super 分区的称为原生动态分区,对应于 Android 的默认动态分区配置;将从低版本升级上来不包含 super 分区的称为改造动态分区,对应于 retrofit 的配置。 本文重点介绍 ...

    Android 动态分区详解(三) 动态分区配置及super.img的生成

    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.imgsuper_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 动态分区配置注意事项

    1. 在动态分区配置中,不再需要以下分区大小设置了,例如:
    BOARD_SYSTEMIMAGE_PARTITION_SIZE := 4294967296 # 4 GB
    BOARD_VENDORIMAGE_PARTITION_SIZE := 536870912 # 512MB
    BOARD_PRODUCTIMAGE_PARTITION_SIZE := 1610612736 # 1.5GB
    
    1. 原生动态分区中,super 分区内的 system, vendor, product 等需要从 GPT 分区表中移除
    2. 应避免将 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 的例子中,

    1. 使用自定义的 TARGET_USE_DYNAMIC_PARTITIONS 作为开关,而不是 PRODUCT_USE_DYNAMIC_PARTITIONS, 不过后者会根据前者设置为 true
    2. BOARD_SUPER_PARTITION_SIZEBOARD_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_LISTSIZE 参数

      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 个地方:

    1. 生成 BUILT_TARGET_FILES_PACKAGE 目标时,将动态分区信息追加到 $(zip_root)/META/misc_info.txt 文件中
    2. 被宏 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.imgsuper_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`规则命令`...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,131,512
精华内容 852,604
关键字:

super