Installer les applications en silence, avec l'autorisation INSTALL_PACKAGES accordée


86

J'essaye d'installer silencieusement apk dans le système. Mon application se trouve dans / system / app et a obtenu l'autorisation "android.permission.INSTALL_PACKAGES"

Cependant, je ne trouve nulle part comment utiliser cette autorisation. J'ai essayé de copier des fichiers dans / data / app et je n'ai pas réussi. J'ai aussi essayé d'utiliser ce code

    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(
            Uri.parse("file:///sdcard/app.apk"),
            "application/vnd.android.package-archive");
    startActivity(intent);

Mais ce code ouvre la boîte de dialogue d'installation standard. Comment puis-je installer l'application silencieusement sans root avec accord android.permission.INSTALL_PACKAGES?

PS J'écris une application qui installera de nombreux apks du dossier dans le système au premier démarrage (remplace l'assistant d'installation). J'en ai besoin pour alléger le firmware.

Si vous pensez que j'écris un virus: Tous les programmes sont installés dans / data / app. L'autorisation Install_packages ne peut être accordée qu'aux programmes de niveau système situés dans / system / app ou signés avec la clé système. Le virus ne peut donc pas y arriver.

Comme dit http://www.mail-archive.com/android-porting@googlegroups.com/msg06281.html, les applications PEUVENT être installées silencieusement si elles ont l'autorisation install_packages. De plus, vous n'avez pas besoin de l'autorisation Install_packages pour installer les packages de manière non silencieuse. Plus http://www.androidzoom.com/android_applications/tools/silent-installer_wgqi.html


9
@Fosco Supposons qu'il fabrique un tel appareil en tant que fabricant d'équipement d'origine?
dascandy

41
@Fosco Qui s'en soucie? C'est une question valable comme le décrit Dascandy. C'est généralement improductif lorsque les gens répondent à des questions comme celles-ci par "Vous ne devriez pas faire ça". Quelle compréhension gagnons-nous avec ce genre de réponse?
ZachM

3
En parlant d'improductif .. vous avez un peu plus de 2 ans de retard à cette soirée Zach, et la question est bien différente de ce qu'elle était à l'origine.
Fosco

2
@Fosco LOL. Je peux également confirmer que cela fonctionne toujours dans le dernier système d'exploitation Android.
POMATu

1
@LarsH Je viens d'installer l'application F-Droid: ils n'installent pas les choses en silence, ils invitent simplement le gestionnaire de packages Android.
Joaquin Iurchuk le

Réponses:


60

Votre premier pari est de regarder dans PackageInstaller natif d' Android . Je recommanderais de modifier cette application comme vous le souhaitez ou d'extraire simplement les fonctionnalités requises.


Plus précisément, si vous examinez PackageInstallerActivity et sa méthode onClickListener:

 public void onClick(View v) {
    if(v == mOk) {
        // Start subactivity to actually install the application
        Intent newIntent = new Intent();
        ...
        newIntent.setClass(this, InstallAppProgress.class);
        ...
        startActivity(newIntent);
        finish();
    } else if(v == mCancel) {
        // Cancel and finish
        finish();
    }
}

Ensuite, vous remarquerez que le programme d'installation réel se trouve dans la classe InstallAppProgress . En inspectant cette classe, vous découvrirez que initViewc'est la fonction principale du programme d'installation, et la dernière chose qu'elle fait est d'appeler PackageManagerla installPackagefonction de:

public void initView() {
...
pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);
}

L'étape suivante consiste à inspecter PackageManager , qui est une classe abstraite. Vous y trouverez la installPackage(...)fonction. La mauvaise nouvelle est qu'il est marqué @hide. Cela signifie qu'il n'est pas directement disponible (vous ne pourrez pas compiler avec l'appel à cette méthode).

 /**
  * @hide
  * ....
  */
  public abstract void installPackage(Uri packageURI,
             IPackageInstallObserver observer, 
             int flags,String installerPackageName); 

Mais vous pourrez accéder à ces méthodes par réflexion.

Si vous êtes intéressé par la manière dont PackageManagerla installPackagefonction de est implémentée, jetez un œil à PackageManagerService .

Sommaire

Vous aurez besoin d'obtenir l'objet du gestionnaire de paquets via Context's getPackageManager(). Ensuite, vous appellerez la installPackagefonction par réflexion.


2
Aidez-moi! Cette technique se traduit par: Provoqué par: java.lang.SecurityException: Ni l'utilisateur 10101 ni le processus actuel n'ont android.permission.INSTALL_PACKAGES. Même si mon application a cette autorisation
gregm

13
Votre application demande cette autorisation, mais Android n'accorde pas cette autorisation aux applications tierces. Consultez LogCatles journaux relatifs aux autorisations.
inazaruk

@inazaruk j'ai lu que les applications installées dans / system / app obtiendront automatiquement l'autorisation d'utiliser install_pakages mais comme décrit dans cet article, cela ne semble pas fonctionner. pouvez-vous me donner quelques indices?
Zorb

3
Comment appeler installPackage via la réflexion? en fait je ne peux pas faire Method method = aPackageManagerClass.getMethod ("installPackage", new Class [] {Uri.class, IPackageInstallObserver.class, Integer.TYPE, String.class}); étant donné que IPackageInstallObserver est également masqué, quelqu'un peut-il m'aider s'il vous plaît, en affichant le code correct pour faire la réflexion ici.
Shilaghae

7
Tous les liens de la réponse sont morts.
Mayur Gangurde

13

J'ai vérifié comment ADB installe les applications.
- Il copie l'APK dans / data / local / tmp
- il exécute 'shell: pm install /data/local/tmp/app.apk'

J'ai essayé de reproduire ce comportement en faisant: (sur PC, en utilisant un câble USB)
adb push app.apk /sdcard/app.apk
adb shell
$ pm install /sdcard/app.apk
Cela fonctionne. L'application est installée.

J'ai créé une application (nommée AppInstall) qui devrait installer l'autre application.
(installé normalement, périphérique non rooté) Oui
:
Runtime.getRuntime().exec("pm install /sdcard/app.apk").waitFor();
Mais cela donne l'erreur:
java.lang.SecurityException: Neither user 10019 nor current process has android.permission.INSTALL_PACKAGES.
il semble que l'erreur soit générée par pm, pas par AppInstall.
Parce que SecurityException n'est pas intercepté par AppInstall et que l'application ne plante pas.

J'ai essayé la même chose sur un appareil enraciné (même application et AppInstall) et cela a fonctionné comme un charme.
(Également normalement installé, pas dans / system ou quoi que ce soit)
AppInstall n'a même pas demandé l'autorisation root.
Mais c'est parce que le shell est toujours #au lieu de $sur cet appareil.

Btw, vous avez besoin de root pour installer une application dans / system, n'est-ce pas?
J'ai essayé adb remount sur le périphérique non rooté et j'ai obtenu:
remount failed: Operation not permitted.
C'est pourquoi je n'ai pas pu essayer le truc / system sur le périphérique non rooté.

Conclusion: vous devriez utiliser un appareil enraciné
J'espère que cela aide :)


Je n'arrive pas à faire fonctionner ça. Il est intéressant de noter que la commande fonctionne correctement dans le shell ADB et ne semble pas fonctionner lorsque j'essaie de l'exécuter par programme.
saulpower

Oui, j'ai le même problème - fonctionne en shell, mais pas lorsqu'il est appelé depuis mon application, même si je l'appelle via su)
velis

Existe-t-il un autre moyen de travailler sur les appareils Google, comme obtenir des autorisations de super-administrateur?
Ramesh Kumar

Si vous voulez des autorisations de super-administrateur, vous devez: 1) rooter votre appareil, 2) installer l'application sur la partition système, 3) ou l'application doit être signée avec la même clé que le système d'exploitation lui-même.
FrankkieNL

1
Cela se produit parce que l'utilisateur ADB et l'utilisateur de votre application ont des autorisations différentes
PHPoenX

11

J'ai récemment mis en œuvre l'installation sans le consentement de l'utilisateur - c'était une application de kiosque pour le niveau d'API 21+ où j'avais un contrôle total sur l'environnement.

Les exigences de base sont

  • Niveau d'API 21+
  • accès root pour installer le programme de mise à jour en tant qu'application privilégiée par le système.

La méthode suivante lit et installe l'APK à partir d'InputStream:

public static boolean installPackage(Context context, InputStream in, String packageName)
            throws IOException {
        PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        params.setAppPackageName(packageName);
        // set params
        int sessionId = packageInstaller.createSession(params);
        PackageInstaller.Session session = packageInstaller.openSession(sessionId);
        OutputStream out = session.openWrite("COSU", 0, -1);
        byte[] buffer = new byte[65536];
        int c;
        while ((c = in.read(buffer)) != -1) {
            out.write(buffer, 0, c);
        }
        session.fsync(out);
        in.close();
        out.close();

        Intent intent = new Intent(context, MainActivity.class);
        intent.putExtra("info", "somedata");  // for extra data if needed..

        Random generator = new Random();

        PendingIntent i = PendingIntent.getActivity(context, generator.nextInt(), intent,PendingIntent.FLAG_UPDATE_CURRENT);
            session.commit(i.getIntentSender());


        return true;
    }

Le code suivant appelle l'installation

 try {
     InputStream is = getResources().openRawResource(R.raw.someapk_source);
                    installPackage(MainActivity.this, is, "com.example.apk");
     } catch (IOException e) {
                    Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
     }

pour que tout fonctionne, vous avez désespérément besoin d'une INSTALL_PACKAGESautorisation, sinon le code ci-dessus échouera silencieusement

<uses-permission
        android:name="android.permission.INSTALL_PACKAGES" />

pour obtenir cette autorisation, vous devez installer votre APK en tant qu'application système qui REQUIERT root (cependant APRÈS avoir installé votre application de mise à jour, il semble fonctionner SANS root)

Pour l'installer en tant qu'application système, j'ai créé un APK signé et l'ai poussé avec

adb push updater.apk /sdcard/updater.apk

puis déplacé vers system/priv-app- ce qui nécessite le remontage de FS (c'est pourquoi la racine est requise)

adb shell
su
mount -o rw,remount /system
mv /sdcard/updater.apk /system/priv-app
chmod 644 /system/priv-app/updater.apk

pour une raison quelconque, cela ne fonctionnait pas avec la version de débogage simple, mais logcat affiche des informations utiles si votre application priv-appn'est pas récupérée pour une raison quelconque.


"pour une raison quelconque, cela ne fonctionnait pas avec une version de débogage simple" Voulez-vous dire que cela fonctionnait dans la version, ou une autre version de débogage moins "simple"?
JM Lord

1
@JMLord Cela fonctionnait avec la version de version signée, et ne fonctionnait pas à la fois avec les versions de débogage signées et non signées - je trouve étrange que cela ne fonctionne pas avec la version de débogage signée I mais je n'ai pas eu le temps d'enquêter. Néanmoins, le journal de connexion système est très important pour savoir si l'APK est installé ou non.
Boris Treukhov

En effet, pour une raison quelconque, l'installation en tant que version était la clé pour obtenir la permission INSTALL_PACKAGES. L'application peut s'exécuter en débogage signé à partir de priv-app, mais la demande d'autorisation a été rejetée. Merci beaucoup!
JM Lord

@BorisTreukhov Hé, puis-je vérifier avec vous à quoi sert le paramètre packageName? J'ai changé le InputStream en FileInputStream mais je reçois ce message d'erreur: Impossible d'analyser /data/app/vmdl676191029.tmp/COSU

comment installer l'application système privée après ces commandes?
user2323471 le

8

Vous devez définir

<uses-permission
    android:name="android.permission.INSTALL_PACKAGES" />

dans votre manifeste, alors si vous êtes dans la partition système (/ system / app) ou si votre application est signée par le fabricant, vous allez avoir l'autorisation INSTALL_PACKAGES.

Ma suggestion est de créer un petit projet android avec un niveau de compatibilité 1.5 utilisé pour appeler installPackages via réflexion et d'exporter un fichier jar avec des méthodes pour installer des packages et pour appeler les méthodes réelles. Ensuite, en important le fichier jar dans votre projet, vous serez prêt à installer des packages.


5

J'ai essayé sur Android 4.2.2 rooté et cette méthode fonctionne pour moi:

private void installApk(String filename) {
    File file = new File(filename); 
    if(file.exists()){
        try {   
            final String command = "pm install -r " + file.getAbsolutePath();
            Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
            proc.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
     }
}

2
La question concernait l'installation d'applications sans root, mais avec l'autorisation système "INSTALL_PACKAGES". Je vois "su" dans votre réponse, donc il faut root.
POMATu

Merci beaucoup pour cette réponse! J'avais le même code mais j'utilisais "adb install -r" au lieu de "pm install -r" et cela ne fonctionnerait PAS pour moi. Vous m'avez fait gagner beaucoup de temps ici!
Jeff.H

@Vladmir j'ai besoin de votre aide. Pouvez-vous me donner un peu de temps. Je vous serai très reconnaissant
twana fra

4

Je n'avais aucune idée de comment faire cela, car personne n'a répondu à ce moment-là, et je n'ai trouvé aucune documentation sur cette autorisation. J'ai donc trouvé ma propre solution. C'est pire que le vôtre, mais c'est quand même une solution.

J'ai installé busybox, qui a défini l'autorisation 777 sur / data / app (je me fiche de la sécurité). Ensuite, il suffit d'exécuter "busybox install" depuis l'application. Cela fonctionne, mais a une grosse fuite de sécurité. Si vous définissez les autorisations 777, aucune racine n'est requise.


3
avez-vous utilisé un code comme celui-ci? Process install; install = Runtime.getRuntime().exec("/system/bin/busybox install " + myAPK.getAbsolutePath()); int iSuccess = install.waitFor();
Quelqu'un quelque part

4

Vous pouvez utiliser l'API masquée android.content.pm.IPackageInstallObserverpar réflexion:

public class PackageManagement {
    public static final int INSTALL_REPLACE_EXISTING = 0x00000002;
    public static final int INSTALL_SUCCEEDED = 1;

    private static Method installPackageMethod;
    private static Method deletePackageMethod;

    static {
        try {
            installPackageMethod = PackageManager.class.getMethod("installPackage", Uri.class, IPackageInstallObserver.class, Integer.TYPE, String.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    public static void installPackage(PackageManager pm, Uri mPackageUri, IPackageInstallObserver observer, int installFlags, String installerPackageName) {
        try {
            installPackageMethod.invoke(pm, mPackageUri, observer, installFlags, installerPackageName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Importez android.content.pm.IPackageInstallObserverdans votre projet. Votre application doit être système. Vous devez activer l'autorisation android.permission.INSTALL_PACKAGESdans votre fichier manifeste.


Avez-vous testé ce code sur Lollipop et Marshamallow? Cela me semble être une approche géniale et je veux l'utiliser
Farhad Faghihi

J'ai testé de ICS à Lollipop
Hermann Poilpre

La ligne à regarder est "votre application doit être système". Je suis assez sûr que cela fonctionnerait sur sucette ou autre - à condition que votre application soit "système", c'est-à-dire que votre application a des autorisations système (fondamentalement root). Dans ce cas, vous pouvez également utiliser le programme d'installation en ligne de commande.
Lassi Kinnunen

1
comment j'appelle la méthode installPackage? Sens, comment puis-je obtenir un IPackageInstallObserver par exemple?
phoebus

Quelle est la valeur de installFlags?
Shivam Kumar le

3

Vous pouvez simplement utiliser la commande adb install pour installer / mettre à jour l'APK en silence. Un exemple de code est ci-dessous

public static void InstallAPK(String filename){
    File file = new File(filename); 
    if(file.exists()){
        try {   
            String command;
            filename = StringUtil.insertEscape(filename);
            command = "adb install -r " + filename;
            Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
            proc.waitFor();
        } catch (Exception e) {
        e.printStackTrace();
        }
     }
  }

Ici, qu'entend-on par StringUtils? Suis-je confronté à une erreur qui ne peut être résolue?
AndroidOptimist

désolé j'aurais dû expliquer. c'est ma classe personnalisée pour les chaînes et cette méthode s'assure que le chemin est correct. vous pouvez l'ignorer
ZeeShaN AbbAs

3
qu'est-ce que la classe StringUtil. pouvez-vous publier la méthode StringUtil.insertEscape ()?. parce que si je commente cette ligne, je reçois une erreur d'exception lors de l'exécution de exec (). Commande: [su, -c, adb install -r /storage/sdcard0/Android/data/com.install.file Merci d'avance
sandeepmaaram

java.io.IOException: Erreur lors de l'exécution de exec (). Commande: [su, -c, adb install -r /storage/emulated/0/download/SwipeAnimation.apk] Répertoire de travail: null Environnement: null - pouvez-vous expliquer l'erreur ..? et si des autorisations dans le manifeste
Sandeep P

1
@ZeeShaNAbbAs après le problème d'enracinement résolu .. merci
Sandeep P

1

Prérequis:

Votre APK doit être signé par le système comme indiqué précédemment. Une façon d'y parvenir consiste à créer vous-même l'image AOSP et à ajouter le code source dans la construction.

Code:

Une fois installé en tant qu'application système, vous pouvez utiliser les méthodes du gestionnaire de packages pour installer et désinstaller un APK comme suit:

Installer:

public boolean install(final String apkPath, final Context context) {
    Log.d(TAG, "Installing apk at " + apkPath);
    try {
        final Uri apkUri = Uri.fromFile(new File(apkPath));
        final String installerPackageName = "MyInstaller";
        context.getPackageManager().installPackage(apkUri, installObserver, PackageManager.INSTALL_REPLACE_EXISTING, installerPackageName);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

Désinstaller:

public boolean uninstall(final String packageName, final Context context) {
    Log.d(TAG, "Uninstalling package " + packageName);
    try {
        context.getPackageManager().deletePackage(packageName, deleteObserver, PackageManager.DELETE_ALL_USERS);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

Pour avoir un rappel une fois que votre APK est installé / désinstallé, vous pouvez utiliser ceci:

/**
 * Callback after a package was installed be it success or failure.
 */
private class InstallObserver implements IPackageInstallObserver {

    @Override
    public void packageInstalled(String packageName, int returnCode) throws RemoteException {

        if (packageName != null) {
            Log.d(TAG, "Successfully installed package " + packageName);
            callback.onAppInstalled(true, packageName);
        } else {
            Log.e(TAG, "Failed to install package.");
            callback.onAppInstalled(false, null);
        }
    }

    @Override
    public IBinder asBinder() {
        return null;
    }
}

/**
 * Callback after a package was deleted be it success or failure.
 */
private class DeleteObserver implements IPackageDeleteObserver {

    @Override
    public void packageDeleted(String packageName, int returnCode) throws RemoteException {
        if (packageName != null) {
            Log.d(TAG, "Successfully uninstalled package " + packageName);
            callback.onAppUninstalled(true, packageName);
        } else {
            Log.e(TAG, "Failed to uninstall package.");
            callback.onAppUninstalled(false, null);
        }
    }

    @Override
    public IBinder asBinder() {
        return null;
    }
}

/**
 * Callback to give the flow back to the calling class.
 */
public interface InstallerCallback {
    void onAppInstalled(final boolean success, final String packageName);
    void onAppUninstalled(final boolean success, final String packageName);
}

===> Testé sur Android 8.1 et a bien fonctionné.


j'ai besoin de ton aide. Pouvez-vous me donner un peu de temps. Je vous serai très reconnaissant
twana fra

Je veux votre aide. J'ai besoin de savoir comment pouvons-nous créer notre propre AOSP
twana fre

0

J'ai créé une application de test pour les installations silencieuses, en utilisant la méthode PackageManager.installPackage.

J'obtiens la méthode installPackage par réflexion et j'ai créé l'interface android.content.pm.IPackageInstallObserver dans mon dossier src (car il est caché dans le package android.content.pm).

Lorsque j'exécute installPackage, j'ai SecurityException avec une indication de chaîne, que mon application n'a pas de android.permission.INSTALL_PACKAGES, mais qu'il est défini dans AndroidManifest.xml.

Donc, je pense qu'il n'est pas possible d'utiliser cette méthode.

PS. J'ai testé sur Android SDK 2.3 et 4.0. Peut-être que cela fonctionnera avec les versions antérieures.


Il fonctionne en 4.1 et 4.0 ainsi que dans toute version Android supérieure à 2.1 (y compris 2.1). J'utilise le SDK 4.0 maintenant. Vous devez l'ajouter au dossier / system / app, sinon votre application n'aura pas les autorisations requises au niveau du système (pas root). Aussi, je suis capable de supprimer des applications en silence avec cette méthode, vérifiez mon autre question liée à la suppression.
POMATu

Oui, cela fonctionne, mais avec les autorisations de root uniquement. Et il n'est pas possible d'installer l'application dans le système / l'application sur un appareil non rooté.
Андрей Москвичёв

Pas avec root, mais avec des autorisations au niveau du système. Vous pouvez l'ajouter à / system / app si vous êtes un fabricant de firmware. Dans mon cas - je le suis (je demande aux fabricants d'appareils d'ajouter mes apks au firmware). Vous ne pourrez pas installer les applications silencieusement d'une autre manière - sinon ce serait une grande faille de sécurité.
POMATu

À propos du trou de sécurité - je suis tout à fait d'accord avec vous. Et ce sera une surprise pour moi, si cette méthode fonctionne avec n'importe quelle application. Comment puis-je installer l'application dans / system / app sans rooter? Je ne suis pas fabricant.
Андрей Москвичёв

1
Sans racine ou reflashing, vous ne pouvez pas.
POMATu

0

Essayez ceci LD_LIBRARY_PATH=/vendor/lib:/system/libavant l'installation de pm. Ça marche bien.


0

Une application tierce ne peut pas installer une application Android lentement. Cependant, une application tierce peut demander au système d'exploitation Android d'installer une application.

Vous devez donc définir ceci:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file:///sdcard/app.apk", "application/vnd.android.package-archive");
startActivity(intent);

Vous pouvez également essayer de l'installer en tant qu'application système pour accorder l'autorisation et ignorer cette définition. (Racine requise)

Vous pouvez exécuter la commande suivante sur votre application tierce pour installer une application sur l'appareil enraciné.

Le code est:

private void installApk(String filename) {
File file = new File(filename); 
if(file.exists()){
    try {   
        final String command = "pm install -r " + file.getAbsolutePath();
        Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
        proc.waitFor();
    } catch (Exception e) {
        e.printStackTrace();
    }
 }
}

J'espère que cette réponse vous sera utile.


0

Il est possible de faire une installation silencieuse sur Android 6 et supérieur. En utilisant la fonction fournie dans la réponse de Boris Treukhov, ignorez tout le reste du message, la racine n'est pas non plus requise.

Installez votre application en tant qu'administrateur de l'appareil, vous pouvez avoir le mode kiosque complet avec une installation silencieuse des mises à jour en arrière-plan.


0

J'ai vérifié toutes les réponses, la conclusion semble être que vous devez d'abord avoir un accès root à l'appareil pour le faire fonctionner.

Mais j'ai trouvé ces articles très utiles. Depuis que je fabrique des appareils "appartenant à l'entreprise".

Comment mettre à jour l'application Android en silence sans interaction de l'utilisateur

Propriétaire d'appareil Android - Application minimale

Voici la documentation de Google sur les "appareils gérés"

Appareil entièrement géré



-6

! / bin / bash

f=/home/cox/myapp.apk   #or $1 if input from terminal.

#backup env var
backup=$LD_LIBRARY_PATH
LD_LIBRARY_PATH=/vendor/lib:/system/lib
myTemp=/sdcard/temp.apk
adb push $f $myTemp
adb shell pm install -r $myTemp
#restore env var
LD_LIBRARY_PATH=$backup

Cela fonctionne pour moi. Je lance ceci sur ubuntu 12.04, sur le terminal shell.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.