IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Android Discussion :

Problème avec la commande "am" dans un script lancé avec ProcessBuilder


Sujet :

Android

  1. #1
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut Problème avec la commande "am" dans un script lancé avec ProcessBuilder
    Salut,

    J'ai besoin de pouvoir exécuter des scripts shell en tant que root dans une application Android écrite en java. J'aimerai pouvoir exécuter des commandes android comme am ou pm et qui nécessite la la présence de la variable d'environnement LD_LIBRARY_PATH=/system/lib. Malheureusement, la commande export ne fonctionne pas et j'en ai réellement besoin :/

    Voici le code Java que j'ai écrit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    private String readScript(String scriptPath) {
     
        String line = null;
        StringBuffer content = new StringBuffer();
     
        try {
     
            // Read the script line by line
            BufferedReader reader = new BufferedReader(new FileReader(scriptPath));
            while ((line = reader.readLine()) != null) {
                content.append(line).append('\n');
            }
            content.append("exit").append('\n');
            reader.close();
     
        } catch (IOException e) {
     
            Log.d(UpdateService.LOG_NAME, "Impossible to read the script : " + e.getMessage());
     
        }
     
        return content.toString();
     
    }
     
    public StringBuffer runScript(String scriptPath) {
     
        String line = null;
        StringBuffer output = new StringBuffer();
     
        try {
     
            // Start the shell process
            ProcessBuilder pb = new ProcessBuilder("su");
            pb.redirectErrorStream(true);
            pb.directory(new File(context.getApplicationInfo().dataDir));
            pb.environment().put("LD_LIBRARY_PATH", "/system/lib");
            Process process = pb.start();
     
            // Execute the script
            OutputStreamWriter os = new OutputStreamWriter(process.getOutputStream());
            os.write(readScript(scriptPath));
            os.flush();
            os.close();
     
            // Get the output of the commands
            BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
            while ((line = in.readLine()) != null) {
                output.append(line).append('\n');
            }
            in.close();
     
        } catch (Exception e) {
     
            Log.d(UpdateService.LOG_NAME, "Error while executing " + scriptPath + " : " + e.getMessage());
     
        }
     
        return output;
     
    }
    Je l'appelle simplement comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Shell = new Shell();
    StringBuffer output = shell.runScript("script.sh");
    Et voici le script que je tente d'exécuter :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    export LD_LIBRARY_PATH=/system/lib
    printenv
    am start -W -n com.android.settings/.Settings
    À la sortie j'obtiens :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    _=/system/bin/printenv
    ANDROID_BOOTLOGO=1
    ANDROID_PROPERTY_WORKSPACE=9,32768
    LOOP_MOUNTPOINT=/mnt/obb
    EXTERNAL_STORAGE=/mnt/sdcard
    ANDROID_DATA=/data
    RANDOM=21985
    ANDROID_SOCKET_zygote=10
    ASEC_MOUNTPOINT=/mnt/asec
    BOOTCLASSPATH=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar
    ANDROID_ROOT=/system
    ANDROID_ASSETS=/system/app
    PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
    Segmentation fault
    Comme on peut le voir, la variable d'environnement initialisée avec la méthode environment() de ProcessBuilder n'est pas settée et la commande export présente dans le scritp ne fonctionne pas non plus et donc la commande am échoue.

    Une idée de la raisons pourquoi cette commande am ne fonctionne pas ?

    Merci beaucoup

  2. #2
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    En cherchant j'ai remarqué que les commandes android am, pm et input sont en réalité des wrappers. Le wrapper de la commande am donne ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    # Script to start "am" on the device, which has a very rudimentary
    # shell.
    #
    base=/system
    export CLASSPATH=$base/framework/am.jar
    exec app_process $base/bin com.android.commands.am.Am "$@"
    J'ai donc eu l'idée de réaliser ce wrapper en C pour pouvoir initialiser un environment propre à la commande avec execve() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
     
    int main(int argc, const char *argv[], const char *envp[]) {
        const char **p;
     
        const int NUM_ARG = 3;
        const char *APP_PROCESS = "/system/bin/app_process";
        const char *BIN = "/system/bin";
        const char *AM = "com.android.commands.am.Am";
     
        const int NUM_ENV = 12;
        const char *ENV[] = {
            "PATH=/usr/bin:/usr/sbin:/bin:/sbin:/system/sbin:/system/bin:/system/xbin:/system/xbin/bb:/data/local/bin",
            "SHELL=/system/bin/sh",
            "MKSH=/system/bin/sh",
            "HOME=/data",
            "HOSTNAME=android",
            "USER=root",
            "LOGNAME=root",
            "TERM=xterm",
            "LD_LIBRARY_PATH=/system/lib/",
            "CLASSPATH=/system/framework/am.jar",
            NULL
        };
     
        int i = 0;
        char *a[argc + NUM_ARG];
        a[i] = (char *)malloc(strlen(APP_PROCESS) + 1);
        strcpy(a[i++], APP_PROCESS);
        a[i] = (char *)malloc(strlen(BIN) + 1);
        strcpy(a[i++], BIN);
        a[i] = (char *)malloc(strlen(AM) + 1);
        strcpy(a[i++], AM);
        p = argv + 1;
        for (; i < argc + NUM_ARG - 1; i++) {
            a[i] = (char *)malloc(strlen(*p) + 1);
            strcpy(a[i], *p++);
        }
        a[i] = (char *)malloc(1);
        a[i] = NULL;
     
        p = envp;
        int envc = 0;
        while (*p++ != NULL) envc++;
     
        char *v[envc + NUM_ENV];
        for (i = 0; i < envc; i++) {
            v[i] = (char *)malloc(strlen(envp[i]) + 1);
            strcpy(v[i], envp[i]);
        }
        p = ENV;
        while (*p != NULL) {
            v[i] = (char *)malloc(strlen(*p) + 1);
            strcpy(v[i++], *p++);
        }
        v[i] = (char *)malloc(1);
        v[i] = NULL;
     
        execve(APP_PROCESS, a, v);
        fprintf(stderr, "am: %s  error: %s\n", APP_PROCESS, strerror(errno));
        for (i = 0; i < argc + NUM_ARG; i++) {
            free(a[i]);
        }
        for (i = 0; i < envc + NUM_ENV; i++) {
            free(v[i]);
        }
     
        return 1;
    }
    Malheureusement ça n'a pas d'impact sur l'exécution de cette commande. Je précise qu'en la testant dans l'application Terminal Emulator ça ne fonctionne pas non plus alors que la commande env montre que la variable LD_LIBRARY_PATH est settée. Par contre la commande fonctionne si je suis connecté à Android en SSH ou via ADB.

    Quel est la différence entre un environnement ProcessBuilder et ADB ?

Discussions similaires

  1. Réponses: 7
    Dernier message: 14/06/2010, 18h24
  2. Réponses: 2
    Dernier message: 11/08/2009, 18h09
  3. Réponses: 4
    Dernier message: 18/09/2008, 18h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo