Aller au contenu

Proposition de modifications pour certaines ROM


Recommended Posts

Bonjour,

comme cette section du Forum est dédiée au développement et aux ROMs alternatives pour notre petit spics, je me suis dit que ce post ne serait pas hors sujet ici.

Je vais en poster une traduction anglaise même si mon anglais laisse à désirer…

Cette information est à destination des développeurs et mainteneurs de ROMs. N'essayez donc pas de mettre en œuvre ce qui est décrit ici sauf si vous comprenez exactement ce que vous êtes en train de faire.

Voici donc une proposition pour faciliter les procédures d'installation et de personnalisation de certaines ROMs Froyo et peut-être GB.

Un certain nombre de ROMs/MOD (celles de Voku, d'IT4ALii3EN ou les NextGen, pour celles que je connais mais il y en a peut-être d'autres…) utilisent la partition data ou la sdcard dans la procédure d'installation de la ROM elle-même.

Ces ROMs nécessitent un voir 2 reboots avant d'être complètement installées. Ces reboots doivent être effectués souvent volontairement par l'utilisateur qui d'ailleurs ignore souvent cette nécessité.

Le principal problème avec ce type de procédure d'installation c'est qu'après un Wipe Data & Cache par exemple, simplement pour réinitialiser son téléphone, sans pour autant souhaiter installer à nouveau la ROM ou installer une nouvelle ROM, tous les éléments présents sur la partition data sont perdus. Et donc le Wipe Data & Cache (Factory Reset) n'a plus sont sens commun de réinitialisation du système.

Par exemple, il convient de ne jamais faire un Wipe D&C immédiatement après avoir installé une de ces ROMs (c'est-à-dire avant de faire le premier reboot de la ROM après son installation). La raison en est simple : l'installation ne pourra plus se produire jusqu'à son terme. Cependant voilà certaines personnes font cela (par exemple, installe zip from sdcard, puis Wipe D&C, puis reboot, …) simplement pour être sur de disposer d'une "clean install" et pour le coups leur ROM ne s'installe pas correctement et va présenter un comportement très erratique (applications qui ne se lance pas, thème très "bizarre", plantage divers,…).

C'est à mon humble avis, un problème auxquels on confronte ses utilisateurs souvent inexpérimentés.

Donc comme je joue actuellement avec la ROM de Voku que je remercie au passage pour son très bon travail, j'ai commencé à la modifier pour contourner le problème que je viens d'évoquer.

Premièrement, j'ai cherché à retirer toutes les chose installées dans la partition data (seules les actions qui ne doivent être exécuté qu'une et une seule fois pourrait être conservées dans le modèle actuel : essentiellement le fix VPN, l'installation du thème, ou la pré-configuration du système qui modifient en fait la partition système ou qu'il est "raisonnable" de perdre après un Factory Reset). Dès lors, les scripts firstboot et secondboot deviennent des exécutables placés dans system/bin…

Le point dure à ce stade, c'est de réussir à installer les libs natives requissent par certaines applications qui sont installées dans /system/app et que les applications en questions s'attendent nécessairement à trouver dans le sous dossier lib de leur dossier de travail respectifs placé sur la partition data (/data/data/dossierDeLApplication/lib). En fait, ces libs sont déjà présentes dans le package .apk de l'application et devrait être facilement extrait pendant l'exécution du script secondboot.

Malheureusement, il semble que l'outil zip embarqué dans le système Android ne marche pas pour ce type de tâche, et je n'ai pas pu trouver jusqu'à présent d'alternative. J'ai donc décidé d'écrire en java un outil très simple et dédié pour faire ça :

/*
* unzuping command line utility
* by LordManta
*/
package jfs.util.zip;

import java.io.File;
import java.io.FileOutputStream;
import java.util.zip.ZipFile;
import java.util.zip.ZipEntry;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class Installer
{
 private static ZipFile zipFile;
 private static Enumeration<? extends ZipEntry> contentFiles;
 private static final Pattern libs = Pattern.compile("^lib\\/.*\\.so$");

 public static void main(final String args[]){
   if(args.length < 1){
     usageMessage();
   }
   final String BASE_DIR = System.getProperty("jfs.util.zip.install.BASE_DIR")+"/";
   for(int i = 0; i< args.length; i++){
     final String arg = args[i];
     final String zipfileName = arg.substring(0, arg.indexOf('='));
     final String packName = arg.substring(arg.indexOf('=')+1);
     try{
        zipFile = new ZipFile(zipfileName);
     }
     catch(java.io.IOException ioe){
       System.err.println("Error: unable to open archive "+zipfileName);
       System.exit(2);
     }
     contentFiles = zipFile.entries();
     while(contentFiles.hasMoreElements()){
       final ZipEntry fileEntry = contentFiles.nextElement();
       final String fileName = fileEntry.getName();
       if(!Pattern.matches("^lib\\/.*\\.so$",fileName)){
         continue;
       }
       File f = new File(fileName);
       final String destName = BASE_DIR+packName+"/lib/"+f.getName();
       System.out.println("Extracting "+destName);
       checkDir(destName);
       if(!fileEntry.isDirectory()){
         try{
           final byte buffer[] = new byte[4096];
           final FileOutputStream extraction = new FileOutputStream(destName);
           final InputStream zipIn = zipFile.getInputStream(fileEntry);
           for(int c = zipIn.read(buffer); c != -1; c = zipIn.read(buffer)){
             extraction.write(buffer,0,c);
           }
           zipIn.close();
           extraction.close();
         }
         catch(java.io.FileNotFoundException fnfe){
           System.err.println("Error cannot write file : "+(destName));
         }
         catch(java.io.IOException ioe){
           System.err.println("Error extracting : "+fileName);
         }
       }
     }
     try{
       zipFile.close();
     }
     catch(java.io.IOException ioe){
     }
   }
 }
 private static void checkDir(final String name){
   final File f = new File(name);
   if(!f.isDirectory()){
     f.getParentFile().mkdirs();
   }
 }
 public static void usageMessage(){
   System.out.println("Usage: jfs_libInstall apKPath=pakageName ...");
   System.exit(1);
 }
}

Pour compiler ce code, voici les quelques lignes de commande à utiliser.

javac jfs/util/zip/Installer.java
jar cvf ../bin/zipper.jar jfs/util/zip/*.class
dx --dex --output=classes.dex jfs/util/zip/*.class
rm -f zipper.jar
aapt add zipper.jar classes.dex

Ce code java doit-être exécuté par la dalvikvm pendant la phase de secondboot comme une simple commande shell d'où l'utilisation du script suivant facilitant la mise en œuvre de l'outil :

#!/system/bin/sh

/system/bin/dalvikvm -Djfs.util.zip.install.BASE_DIR="/data/data/" -cp /system/bin/zipper.jar jfs.util.zip.Installer $@

#EOF

Pour le moment, le script et le fichier jar correspondant sont placés dans le dossier bin du système, mais je ne suis pas très sur des implications de ce choix notamment en terme de sécurité,…

Maintenant grâce à cet outil, il devient très facile de mettre n'importe quelle application dans system/app. Si cette application utilise des libs natives, elles seront automatiquement extraites et installée. Pour y parvenir, il faudra remplacer (exemple de la Voku) :

/system/xbin/cp -rf /data/lib/rockplayer_armv6/*.so /data/data/com.redirectin.rockplayer.android.unified/lib/;
/system/xbin/cp -rf /system/bin/rockplayer_sgm/*.so /data/data/org.freecoder.android.cmplayer/lib/;
/system/xbin/cp -rf /data/lib/estrongs/*.so /data/data/com.estrongs.android.pop/lib/;
/system/xbin/cp -rf /data/lib/quickpic/*.so /data/data/com.alensw.PicFolder/lib
/system/xbin/cp -rf /data/lib/qqplayer/*.so /data/data/com.tencent.research.drop/lib/;
/system/xbin/cp -rf /data/lib/opera_mini/*.so /data/data/com.opera.mini.android/lib/;
busybox rm -r /data/lib/;

par le code suivant :

echo "--- Installing libraries"
/system/xbin/jfs_libsInstall $(cat /data/system/packages.xml |grep '<package '|sed -e 's/<package name="//'|sed -e 's/" codePath="/=/'|sed -e 's/".*//'|awk -F = '{print $2"="$1}')
chown system:system $(find /data/data -name '*.so')
chmod 755 $(find /data/data -name '*.so')

Il n'est plus nécessaire d'extraire manuellement, les libs natives et de les installer sur la partition data en modifiant le script secondboot pour ajouter une nouvelle ligne à chaque fois, qu'une nouvelle appui est installée…

La dernière chose importante à faire pour être sur que les script de firstboot et secondboot seront exécuté correctement après un Wipe D&C… L'idée est simple et repose essentiellement sur la modification du script de démarrage 02secondboot servant à exécuter le script secondboot non plus sur la présence du fichier secondboot.sh dans la partition data mais, sur l'absence d'un fichier, comme par exemple un fichier /data/install.log que j'utilise par exemple ici pour positionner des variables renseignant sur les étape franchies dans la procédure d'installation.

JFS_PHASE_1=false
JFS_PHASE_2=true
if [ -e /data/install.log ]
then
 . /data/install.log
fi
if $JFS_PHASE_1
then
 if $JFS_PHASE_2
 then
   /system/bin/secondboot
   echo 'JFS_PHASE_2=false' >> /data/install.log
 fi
fi

Les opérations qui ne devrait être exécuté qu'une fois pour toutes comme par exemple le fix du VPN doivent être modifiés pour ne se déclencher qu'une seule fois par exemple sur l'existence de su.orig, etc… Les fichiers de configuration pour des applications spécifiques pourraient être stockés dans un tar ball compressé appelé par exemple /system/.installFiles.tgz, et décompressé dans le script secondboot…

De même le script de démarrage 03firstboot pourrait devenir quelque chose du genre :

if [ -e /data/install.log ]
then
 . /data/install.log
else
 /system/bin/firstboot.sh;
 echo 'JFS_PHASE_1=true' >> /data/install.log
fi
if [ -e /data/samdroidtools.sh ];
then
   echo "--- Executing samdroidtools.sh";
   /system/bin/sh /data/samdroidtools.sh;
fi;

Les gains obtenus par l'application de cette méthode sont :

  1. une implantation générique du script secondboot permettant à n'importe quelle application utilisant des libs natives d'être placé dans /system/app de façon transparente
  2. Allège le zip de la ROM car les lis n'ont plus besoin d'être dupliquées.
  3. Rend son sens commun à l'opération Wipe Data & Cache : (Factory Reset)

Lien vers le commentaire
Partager sur d’autres sites

I wrote this in english also for non french developers but my english is not so good…

Here is a proposal to make the installation and customization of ROMs easier.

Many ROMs/MOD (Voku's ones, IT4ALii3EN's ones or NextGen, as far as I know but perhaps others…) use the data partition or the sdcard to proceed late part of the installation procedure of the ROM itself.

These ROMs needs 1 or even two reboots before being fully functional. And those reboots should be performed voluntary by the user that indeed often doesn't even know this point.

The main issue of this kind of installation procedure is that after a Wipe Data & Cache for example just to cleanup things and not to install a new ROM, all things put on data partition is lost (in fact things are already cleaned up by installation scripts themselves). So the Wipe Data & Cache doesn't have the usual meaning of a "factory reset".

As an example, you should never do a Wipe D&C just after installing these king of ROMs (i.e. before rebooting frost the first time the ROM) because the installation could not complete. Some people do that (install zip from sdcard, then Wipe D&C, then reboot, …) to be sure of a clean install and their ROM do not install well (of course only cleaning cache is not a problem).

In addition some ROM (at least Voku's, NextGen) need 2 reboot to be fully installed (see firstboot and secondboot scripts in data partition)…

IMHO, this could be an issue especially with inexperimented users.

So as I'm playing with the Voku's ROM for now (very great job man, I didn't have tried to get it from your source for now, but hope to do it soon, I get compilation errors on egl... but that's another story), I have tried to modify it to overcome this problem.

First, I want to remove things in data (only really one-shot scripts remain here : essentially the VPN fix, theme installation, pre-configuration of the system). firstboot and secondboot scripts become executable ones in system/bin. Then the tricky point here is how do one get native libs needed by some apps that are installed in /system/app and needed to be found in their respective folder in the data partition? In fact, those libs are already present in the .apk package and should be easily extracted during the execution of the secondboot script directly from the apk.

Unfortunately, the zip tool embedded in the android system doesn't work for that task, and I have not found any alternative. So, I decided to write in java a very simple tool for that :

/*
* unzuping command line utility
* by LordManta
*/
package jfs.util.zip;

import java.io.File;
import java.io.FileOutputStream;
import java.util.zip.ZipFile;
import java.util.zip.ZipEntry;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class Installer
{
 private static ZipFile zipFile;
 private static Enumeration<? extends ZipEntry> contentFiles;
 private static final Pattern libs = Pattern.compile("^lib\\/.*\\.so$");

 public static void main(final String args[]){
   if(args.length < 1){
     usageMessage();
   }
   final String BASE_DIR = System.getProperty("jfs.util.zip.install.BASE_DIR")+"/";
   for(int i = 0; i< args.length; i++){
     final String arg = args[i];
     final String zipfileName = arg.substring(0, arg.indexOf('='));
     final String packName = arg.substring(arg.indexOf('=')+1);
     try{
        zipFile = new ZipFile(zipfileName);
     }
     catch(java.io.IOException ioe){
       System.err.println("Error: unable to open archive "+zipfileName);
       System.exit(2);
     }
     contentFiles = zipFile.entries();
     while(contentFiles.hasMoreElements()){
       final ZipEntry fileEntry = contentFiles.nextElement();
       final String fileName = fileEntry.getName();
       if(!Pattern.matches("^lib\\/.*\\.so$",fileName)){
         continue;
       }
       File f = new File(fileName);
       final String destName = BASE_DIR+packName+"/lib/"+f.getName();
       System.out.println("Extracting "+destName);
       checkDir(destName);
       if(!fileEntry.isDirectory()){
         try{
           final byte buffer[] = new byte[4096];
           final FileOutputStream extraction = new FileOutputStream(destName);
           final InputStream zipIn = zipFile.getInputStream(fileEntry);
           for(int c = zipIn.read(buffer); c != -1; c = zipIn.read(buffer)){
             extraction.write(buffer,0,c);
           }
           zipIn.close();
           extraction.close();
         }
         catch(java.io.FileNotFoundException fnfe){
           System.err.println("Error cannot write file : "+(destName));
         }
         catch(java.io.IOException ioe){
           System.err.println("Error extracting : "+fileName);
         }
       }
     }
     try{
       zipFile.close();
     }
     catch(java.io.IOException ioe){
     }
   }
 }
 private static void checkDir(final String name){
   final File f = new File(name);
   if(!f.isDirectory()){
     f.getParentFile().mkdirs();
   }
 }
 public static void usageMessage(){
   System.out.println("Usage: jfs_libInstall apKPath=pakageName ...");
   System.exit(1);
 }
}

To compile this code here are the few command lines to use.

javac jfs/util/zip/Installer.java
jar cvf ../bin/zipper.jar jfs/util/zip/*.class
dx --dex --output=classes.dex jfs/util/zip/*.class
rm -f zipper.jar
aapt add zipper.jar classes.dex

This Java code should be executed by the dalvikvm during the second boot as a simple shell command so a wrapper script is provided :

#!/system/bin/sh

/system/bin/dalvikvm -Djfs.util.zip.install.BASE_DIR="/data/data/" -cp /system/bin/zipper.jar jfs.util.zip.Installer $@

#EOF

For the moment, the script and the jar file are put in the bin directory, but I'm not sure of the implications of that choice,...

Now using that tool, it is very simple to put any apps you want in system/app that has native libs in it because all the libs are extracted and installed automatically during the second boot of the ROM. to do that on has to modify the secondboot file replacing for example :

/system/xbin/cp -rf /data/lib/rockplayer_armv6/*.so /data/data/com.redirectin.rockplayer.android.unified/lib/;
/system/xbin/cp -rf /system/bin/rockplayer_sgm/*.so /data/data/org.freecoder.android.cmplayer/lib/;
/system/xbin/cp -rf /data/lib/estrongs/*.so /data/data/com.estrongs.android.pop/lib/;
/system/xbin/cp -rf /data/lib/quickpic/*.so /data/data/com.alensw.PicFolder/lib
/system/xbin/cp -rf /data/lib/qqplayer/*.so /data/data/com.tencent.research.drop/lib/;
/system/xbin/cp -rf /data/lib/opera_mini/*.so /data/data/com.opera.mini.android/lib/;
busybox rm -r /data/lib/;

by

echo "--- Installing libraries"
/system/xbin/jfs_libsInstall $(cat /data/system/packages.xml |grep '<package '|sed -e 's/<package name="//'|sed -e 's/" codePath="/=/'|sed -e 's/".*//'|awk -F = '{print $2"="$1}')
chown system:system $(find /data/data -name '*.so')
chmod 755 $(find /data/data -name '*.so')

Doing so you do not need to extract natively manually and put them in data partition and modify the secondboot file to add one new line each time you add a new app with native libs…

The last thing to do is to be sure that firstboot and second boot will be properly executed after a Wipe D&C… the idea is simple and is essentially a modification of the 02secondboot to execute the secondboot script not on the presence of the secondboot.sh file but on the absence of a file for example /data/install.log that I use here to set variable about installation stages.

JFS_PHASE_1=false
JFS_PHASE_2=true
if [ -e /data/install.log ]
then
 . /data/install.log
fi
if $JFS_PHASE_1
then
 if $JFS_PHASE_2
 then
   /system/bin/secondboot
   echo 'JFS_PHASE_2=false' >> /data/install.log
 fi
fi

One shot operation for example such as the VPN fix should rely on the existence of su.orig to be triggered or not etc… Configuration files for specific applications should be put in a tar ball compressed archive in /system/.installFiles.tgz for instance, …

The 03firstboot should write something like :

if [ -e /data/install.log ]
then
 . /data/install.log
else
 /system/bin/firstboot.sh;
 echo 'JFS_PHASE_1=true' >> /data/install.log
fi
if [ -e /data/samdroidtools.sh ];
then
   echo "--- Executing samdroidtools.sh";
   /system/bin/sh /data/samdroidtools.sh;
fi;

The benefit of this solution are :

  1. Generic implantation of the secondboot script allowing any apps with native libs to be transarently put in /system/app
  2. Makes the zip liter cause of no duplication of the native libs
  3. Makes the Wipe Data & Cache (Factory Reset) consistent

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...