浏览模式: 标准 | 列表
11月
26

将ROM分解为IPK

 前面6节基本上已经把ROM定制的具体过程都讲完了。从这节开始,我们来讨论一点高级内容。不过本人水平有限,以下内容算是抛砖引玉了。

前面在ROM文件结构一节中,我们已经提到,rootfs下的大部分文件都是预安装好的包,那我们有没有可能将这些包都还原为ipk呢?

当然可以。

下面我们就来看一下这个过程该如何实现。

首先我们需要把ROM分解,分解的工具最方便的还是使用MetaDoctor里面的unpack-doctor这个脚本。在Linux下,我们最好是用root帐号来执行这个命令,以保证包中文件的权限不会改变。

展开之后,我们可以在rootfs/usr/lib/ipkg/info中找到所有已安装的包的control文件,因为每个包都有一个对应的control,所以我们以这个control文件为依据,就可以列出系统内所有的包。

之后循环读取这些control文件名,然后通过它来获取包名,然后用包名为该包建立一个目录,在其中再创建CONTROL和data这两个目录,然后把control复制(或移动)到CONTROL目录下,然后把该包对应的preinst、postinst、prerm、postrm脚本也都统统复制(或移动)到CONTROL目录下,最后再根据list文件中的内容,将该包中包含的文件及其目录复制(或移动)到data目录下,最后使用ipkg-build脚本,对该目录进行打包就可以啦。

下面是将ROM分解为ipk文件的完整脚本:

  1. #!/bin/sh  
  2.   
  3. [ -f $1 ] || exit 1  
  4.   
  5. currpath=`pwd`  
  6. $currpath/unpack-doctor $1  
  7.   
  8. NAME=`basename $1 .jar`  
  9.   
  10. rm -rf $NAME/ipkgs $NAME/build  
  11. mkdir -p $NAME/ipkgs $NAME/build  
  12.   
  13. cd $NAME/ipkgs  
  14.   
  15. ROOTFS=$currpath/$NAME/rootfs  
  16. INFOPATH=$ROOTFS/usr/lib/ipkg/info  
  17.   
  18. ls $INFOPATH/*.control | while read control; do  
  19.     package=`basename $control .control`  
  20.     PACKAGE=$currpath/$NAME/build/$package  
  21.     CONTROL=$PACKAGE/CONTROL  
  22.     data=$PACKAGE/data  
  23.     mkdir -p $CONTROL $data  
  24.     cp $control $CONTROL/control  
  25.     if [ -f $INFOPATH/$package.preinst ]; then  
  26.         mv $INFOPATH/$package.preinst $CONTROL/preinst  
  27.     fi  
  28.     if [ -f $INFOPATH/$package.postinst ]; then  
  29.         mv $INFOPATH/$package.postinst $CONTROL/postinst  
  30.     fi  
  31.     if [ -f $INFOPATH/$package.prerm ]; then  
  32.         mv $INFOPATH/$package.prerm $CONTROL/prerm  
  33.     fi  
  34.     if [ -f $INFOPATH/$package.postrm ]; then  
  35.         mv $INFOPATH/$package.postrm $CONTROL/postrm  
  36.     fi  
  37.     if [ -f $INFOPATH/$package.list ]; then  
  38.         cat $INFOPATH/$package.list | while read filename; do  
  39.             pathname=`dirname "$filename"`  
  40.             mkdir -p "$data/$pathname"  
  41.             mv -f -T "$ROOTFS/$filename" "$data/$filename"  
  42.         done  
  43.         $currpath/ipkg-build $PACKAGE  
  44.     fi  
  45. done  
  46.   
  47. cd $currpath  

把这个保存为一个脚本,然后在同一个目录下放上unpack-doctor和ipkg-build脚本,然后再把要展开的ROM放在这个目录下,这个脚本的目录下运行脚本后面跟上ROM名称,就可以将ROM分解为ipk了。

理解了以上脚本之后,根据该原理,就也可以很方便的完成ROM杂交,ROM内置安装包移除等脚本了。这些脚本的编写就看各位高手的啦。

11月
26

集成安装IPK

 完成了ipk的打包之后,我们需要将修改过的或者新添加的ipk包加入到我们自己要定制的ROM当中。但ipk包的安装位置是有区别的,一种是安装到root的ipk包,另一种是安装到/media/cryptofs/apps下的ipk包。

安装到root的ipk包,有两种集成方式,一种是预安装方式,一种是放在<carrier>.tar中(<carrier>表示att、wr、verizon等)。

预安装方式采用跟原始ROM中那些预安装的包一样的方法,MetaDoctor里面有两个选项EXTRA_ROOTFS_IPKGS和EXTRA_ROOTFS_TARBALL,把事先修改过的包手动展开按照ROM文件结构打包成tar文件,然后放在跟Makefile相同的目录下,然后设定好这个EXTRA_ROOTFS_TARBALL这个参数,然后把跟这个tar里面有关的包名放在EXTRA_ROOTFS_IPKGS这个参数里,就可以了。这种方式比较麻烦,而且容易出错,修改之后对root分区镜像的影响是永久性的,所以,这不是推荐的方式。

而放在<carrier>.tar中则非常方便。但是仍然有需要注意的问题,如果ROM中已经有预安装的同名的包,需要先手动从rootfs镜像中删除。删除方法不难,但比较繁琐:

到rootfs/usr/lib/ipkg/info下找到跟要删除的包名相关的所有文件(control,list,preinst等),根据这里面的list文件中的内容,找到这里面的这些文件一一删除,修改rootfs/md5sums.tar里面的md5sums文件,将其中跟这个包有关的所有内容删除。然后根据control文件中所描述的构架到rootfs/usr/lib/ipkg/lists中找到对应构架的那个文件,打开它将其中关于这个包的部分删除掉。打开rootfs/usr/lib/ipkg/status,将其中跟这个包有关的内容删除掉。把rootfs/usr/lib/ipkg/info中的跟这个包有关的所有文件删除。最后再次修改rootfs/md5sums.tar里面的md5sums文件,将修改过的rootfs/usr/lib/ipkg/lists/oe-<arch>和rootfs/usr/lib/ipkg/status这两个的md5sum值重新计算后更新。

以上步骤可以通过写一个脚本来自动完成,有兴趣的同学可以自己来写。

另一种是安装到/media/cryptofs/apps中的包,这些包实际上并不是在刷机过程中安装的,而是在刷机之后配置完毕的第一次启动时安装的。

在webOS 2.1中,系统给出了一个这样的例子。那就是系统里内置的app-ipkgs这个包。这个包在webOS 2.2.x和webOS 3.x中有更新,更新之后的安装方式有些变化,我们暂时不管,我们先来看看webOS 2.1中的app-ipkgs这个包是怎么做的。

这个包包含2个部分,一部分是/usr/palm/ipkgs这个目录下的一些安装包、图标和一个manifest.json文件,另一部分是/etc/event.d/app-install这个安装脚本。

/usr/palm/ipkgs下的安装包没什么好说的,单说manifest.json这个文件,这里面是安装包的一些包信息,如果你要安装的包的信息不在这个文件里,也没有什么太大影响。如果在这个文件里,在软件管理器中就看不到这个软件的删除选项。但在启动器中仍然可以通过按住白方块点图标删除。

我们重点看一下/etc/event.d/app-install这个脚本。

2.1的这个脚本很简单,就是将/usr/palm/ipkgs下的所有ipk列出来然后通过循环方式执行安装。

在安装时首先将安装文件复制到/media/internal/downloads下,其实复制到/media/internal的其它任何自建的目录下都可以,这样做是因为安装时,安装位置是需要可写入的,因为在安装过程中安装器会自动创建一个tmp目录。另外,如果要保证安装目录可写,也可以用rootfs_open –w的方法。这样可以省去文件的复制过程。

然后通过:

ipkg –o /media/cryptofs/apps install $package

命令安装。

最后通过:

luna-send -n 1 palm://com.palm.applicationManager/forceSingleAppScan '{"id":"'$pkg'"}'

来使安装的软件生效(桌面上就可以看到图标了)。

这样的一个安装过程,对于安装没有安装依赖顺序,没有postinst脚本的ipk来说是足够了。

但对于带有postinst脚本、prerm等脚本的应用来说还是有些问题的。因为ipkg –o 方式安装时,不会自动执行postinst脚本,这就使得带有postinst脚本的安装程序不能被完全安装。

我们可以在ipkg –o 之后加上这样一段:

  1. #check if install succeeded, then run postinst if needed  
  2. if [ -f $APPS/usr/lib/ipkg/info/$pkg.control ] ; then  
  3.     if [ -f $APPS/usr/lib/ipkg/info/$pkg.prerm ] ; then  
  4.         if [ ! -f $APPS/.scripts/$pkg/pmPreRemove.script ] ; then  
  5.             /bin/mkdir -m 777 -p $APPS/.scripts/$pkg  
  6.             /bin/cp -f $APPS/usr/lib/ipkg/info/$pkg.prerm $APPS/.scripts/$pkg/pmPreRemove.script  
  7.         fi  
  8.     fi  
  9.     if [ -f $APPS/usr/lib/ipkg/info/$pkg.postinst ] ; then  
  10.         echo "$UPSTART_JOB: Running $pkg.postinst" | logger  
  11.         export IPKG_OFFLINE_ROOT=$APPS ; /bin/sh $APPS/usr/lib/ipkg/info/$pkg.postinst  
  12.     fi  
  13. fi  

就实现了这些安装脚本的处理。

但是对于有安装依赖顺序的ipk来说,通过for循环目录可能无法保证正确的安装顺序,所以我们可以人为的来写一个安装文件列表,比如叫packages(其实叫什么都行),里面一行一个ipk文件名,例如:

  1. com.palm.app.findapps_2.0.23300_all.ipk  
  2. org.webosinternals.preware_1.8.5_arm.ipk  
  3. org.webosinternals.diffstat_1.45-1_armv7.ipk  
  4. org.webosinternals.lsdiff_0.3.1-1_armv7.ipk  
  5. org.webosinternals.patch_2.5.9-4_armv7.ipk  
  6. org.webosinternals.unzip_6.0-1_armv7.ipk  
  7. org.webosinternals.zip_3.0-1_armv7.ipk  
  8. ca.canucksoftware.js-service-framework_1.0.1_all.ipk  
  9. ca.canucksoftware.filemgr_2.0.7_all.ipk  
  10. ca.canucksoftware.internalz_1.5.0_all.ipk  
  11. org.webosinternals.patches.misc-unthrottle-download-manager_2.1.0-160_all.ipk  

这样一个格式,只要这个文件里的包安装顺序正确,就可以用for循环来读取这个文件来保证顺序了。

然后还有一点小问题,就是如果安装的程序里包含有服务,例如上面例子中的filemgr,这样安装之后,可能服务无法自动启动,原因是在/var/palm/ls2/roles/prv和pub下没有生成服务规则文件。本来这些文件应该是在程序安装之后,系统根据usr/palm/services/包名/services.json自动生成的,但既然系统没有生成,那我们就自己创建一下这两个文件,加入下面的代码可以完成规则文件的创建:

  1.         if [ -f $APPS/usr/palm/services/$pkg/services.json ] ; then  
  2.             echo "{  
  3.     \"role\": {  
  4.         \"exeName\":\"js\",  
  5.         \"type\": \"regular\",  
  6.         \"allowedNames\": [\"$pkg\"]  
  7.     },  
  8.     \"permissions\": [  
  9.         {  
  10.          \"service\":\"$pkg\",  
  11.          \"inbound\":[\"*\"],  
  12.          \"outbound\":[\"*\"]  
  13.         }  
  14.     ]  
  15. }" > /var/palm/ls2/roles/prv/$pkg.json  
  16.             chmod +x /var/palm/ls2/roles/prv/$pkg.json  
  17.             cp /var/palm/ls2/roles/prv/$pkg.json /var/palm/ls2/roles/pub/$pkg.json  
  18.         fi  

最后,我们修改之后的完整脚本是这样子的:

  1. # -*- mode: shell-script; -*-  
  2.   
  3. start on stopped configurator  
  4.   
  5. script  
  6.     rootfs_open -w  
  7.   
  8.     APPS=/media/cryptofs/apps  
  9.     IPK_DIR=/usr/palm/ipkgs  
  10.   
  11.     for package in $(cat $IPK_DIR/packages)  
  12.     do  
  13.         echo "$UPSTART_JOB: attempt to install $package" | logger  
  14.   
  15.         #call luna-send to begin installation  
  16.         ipkg -o $APPS install $IPK_DIR/$package | logger  
  17.   
  18.         # Get the pkg name from the file name.  
  19.         local bname=${package##*/}  
  20.         local rname=${bname%.ipk}  
  21.         local pkg=${rname%%_*}  
  22.   
  23.         if [ -f $APPS/usr/palm/services/$pkg/services.json ] ; then  
  24.             echo "{  
  25.     \"role\": {  
  26.         \"exeName\":\"js\",  
  27.         \"type\": \"regular\",  
  28.         \"allowedNames\": [\"$pkg\"]  
  29.     },  
  30.     \"permissions\": [  
  31.         {  
  32.          \"service\":\"$pkg\",  
  33.          \"inbound\":[\"*\"],  
  34.          \"outbound\":[\"*\"]  
  35.         }  
  36.     ]  
  37. }" > /var/palm/ls2/roles/prv/$pkg.json  
  38.             chmod +x /var/palm/ls2/roles/prv/$pkg.json  
  39.             cp /var/palm/ls2/roles/prv/$pkg.json /var/palm/ls2/roles/pub/$pkg.json  
  40.         fi  
  41.   
  42.         #check if install succeeded, then run postinst if needed  
  43.         if [ -f $APPS/usr/lib/ipkg/info/$pkg.control ] ; then  
  44.             if [ -f $APPS/usr/lib/ipkg/info/$pkg.prerm ] ; then  
  45.                 if [ ! -f $APPS/.scripts/$pkg/pmPreRemove.script ] ; then  
  46.                     /bin/mkdir -m 777 -p $APPS/.scripts/$pkg  
  47.                     /bin/cp -f $APPS/usr/lib/ipkg/info/$pkg.prerm $APPS/.scripts/$pkg/pmPreRemove.script  
  48.                 fi  
  49.             fi  
  50.             if [ -f $APPS/usr/lib/ipkg/info/$pkg.postinst ] ; then  
  51.                 echo "$UPSTART_JOB: Running $pkg.postinst" | logger  
  52.                 export IPKG_OFFLINE_ROOT=$APPS ; /bin/sh $APPS/usr/lib/ipkg/info/$pkg.postinst  
  53.             fi  
  54.         fi  
  55.   
  56.         echo "$UPSTART_JOB: attempt to scan $pkg" | logger  
  57.   
  58.         # Have the applicationManager rescan the pkg so that it will   
  59.         # show up in the launcher.  
  60.         returnVal=$(luna-send -n 1 palm://com.palm.applicationManager/forceSingleAppScan \  
  61.             '{"id":"'$pkg'"}' 2>&1)  
  62.   
  63.         logger "$UPSTART_JOB: returnVal is $returnVal"  
  64.     done  
  65. end script  

现在我们可以把这个包单独拿出来,然后把rootfs下的这个预先安装的这个包删掉。最后修改之后,放在<carrier>.tar里面就可以啦。

当然,更好的方法是,不要动系统的这个app-ipkgs。自己创建一个类似的包,脚本按照自己设置的目录来写。最后单独打一个包,名字不要跟系统已有的包冲突,最后放在<carrier>.tar中就可以了。自己创建类似安装包的好处是,它可以减少你对rootfs的修改,保证系统自带的升级程序不会被破坏,另外还能适用于1.x、2.2.x和3.x系统,而不仅仅局限于2.1.x系统。

11月
04

WebOS ROM修改入门教程