Home | History | Annotate | Download | only in pm
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.pm;
     18 
     19 import android.content.pm.PackageStats;
     20 import android.net.LocalSocket;
     21 import android.net.LocalSocketAddress;
     22 import android.util.Slog;
     23 
     24 import java.io.IOException;
     25 import java.io.InputStream;
     26 import java.io.OutputStream;
     27 
     28 public final class Installer {
     29     private static final String TAG = "Installer";
     30 
     31     private static final boolean LOCAL_DEBUG = false;
     32 
     33     InputStream mIn;
     34 
     35     OutputStream mOut;
     36 
     37     LocalSocket mSocket;
     38 
     39     byte buf[] = new byte[1024];
     40 
     41     int buflen = 0;
     42 
     43     private boolean connect() {
     44         if (mSocket != null) {
     45             return true;
     46         }
     47         Slog.i(TAG, "connecting...");
     48         try {
     49             mSocket = new LocalSocket();
     50 
     51             LocalSocketAddress address = new LocalSocketAddress("installd",
     52                     LocalSocketAddress.Namespace.RESERVED);
     53 
     54             mSocket.connect(address);
     55 
     56             mIn = mSocket.getInputStream();
     57             mOut = mSocket.getOutputStream();
     58         } catch (IOException ex) {
     59             disconnect();
     60             return false;
     61         }
     62         return true;
     63     }
     64 
     65     private void disconnect() {
     66         Slog.i(TAG, "disconnecting...");
     67         try {
     68             if (mSocket != null)
     69                 mSocket.close();
     70         } catch (IOException ex) {
     71         }
     72         try {
     73             if (mIn != null)
     74                 mIn.close();
     75         } catch (IOException ex) {
     76         }
     77         try {
     78             if (mOut != null)
     79                 mOut.close();
     80         } catch (IOException ex) {
     81         }
     82         mSocket = null;
     83         mIn = null;
     84         mOut = null;
     85     }
     86 
     87     private boolean readBytes(byte buffer[], int len) {
     88         int off = 0, count;
     89         if (len < 0)
     90             return false;
     91         while (off != len) {
     92             try {
     93                 count = mIn.read(buffer, off, len - off);
     94                 if (count <= 0) {
     95                     Slog.e(TAG, "read error " + count);
     96                     break;
     97                 }
     98                 off += count;
     99             } catch (IOException ex) {
    100                 Slog.e(TAG, "read exception");
    101                 break;
    102             }
    103         }
    104         if (LOCAL_DEBUG) {
    105             Slog.i(TAG, "read " + len + " bytes");
    106         }
    107         if (off == len)
    108             return true;
    109         disconnect();
    110         return false;
    111     }
    112 
    113     private boolean readReply() {
    114         int len;
    115         buflen = 0;
    116         if (!readBytes(buf, 2))
    117             return false;
    118         len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
    119         if ((len < 1) || (len > 1024)) {
    120             Slog.e(TAG, "invalid reply length (" + len + ")");
    121             disconnect();
    122             return false;
    123         }
    124         if (!readBytes(buf, len))
    125             return false;
    126         buflen = len;
    127         return true;
    128     }
    129 
    130     private boolean writeCommand(String _cmd) {
    131         byte[] cmd = _cmd.getBytes();
    132         int len = cmd.length;
    133         if ((len < 1) || (len > 1024))
    134             return false;
    135         buf[0] = (byte) (len & 0xff);
    136         buf[1] = (byte) ((len >> 8) & 0xff);
    137         try {
    138             mOut.write(buf, 0, 2);
    139             mOut.write(cmd, 0, len);
    140         } catch (IOException ex) {
    141             Slog.e(TAG, "write error");
    142             disconnect();
    143             return false;
    144         }
    145         return true;
    146     }
    147 
    148     private synchronized String transaction(String cmd) {
    149         if (!connect()) {
    150             Slog.e(TAG, "connection failed");
    151             return "-1";
    152         }
    153 
    154         if (!writeCommand(cmd)) {
    155             /*
    156              * If installd died and restarted in the background (unlikely but
    157              * possible) we'll fail on the next write (this one). Try to
    158              * reconnect and write the command one more time before giving up.
    159              */
    160             Slog.e(TAG, "write command failed? reconnect!");
    161             if (!connect() || !writeCommand(cmd)) {
    162                 return "-1";
    163             }
    164         }
    165         if (LOCAL_DEBUG) {
    166             Slog.i(TAG, "send: '" + cmd + "'");
    167         }
    168         if (readReply()) {
    169             String s = new String(buf, 0, buflen);
    170             if (LOCAL_DEBUG) {
    171                 Slog.i(TAG, "recv: '" + s + "'");
    172             }
    173             return s;
    174         } else {
    175             if (LOCAL_DEBUG) {
    176                 Slog.i(TAG, "fail");
    177             }
    178             return "-1";
    179         }
    180     }
    181 
    182     private int execute(String cmd) {
    183         String res = transaction(cmd);
    184         try {
    185             return Integer.parseInt(res);
    186         } catch (NumberFormatException ex) {
    187             return -1;
    188         }
    189     }
    190 
    191     public int install(String name, int uid, int gid, String seinfo) {
    192         StringBuilder builder = new StringBuilder("install");
    193         builder.append(' ');
    194         builder.append(name);
    195         builder.append(' ');
    196         builder.append(uid);
    197         builder.append(' ');
    198         builder.append(gid);
    199         builder.append(' ');
    200         builder.append(seinfo != null ? seinfo : "!");
    201         return execute(builder.toString());
    202     }
    203 
    204     public int dexopt(String apkPath, int uid, boolean isPublic) {
    205         StringBuilder builder = new StringBuilder("dexopt");
    206         builder.append(' ');
    207         builder.append(apkPath);
    208         builder.append(' ');
    209         builder.append(uid);
    210         builder.append(isPublic ? " 1" : " 0");
    211         return execute(builder.toString());
    212     }
    213 
    214     public int movedex(String srcPath, String dstPath) {
    215         StringBuilder builder = new StringBuilder("movedex");
    216         builder.append(' ');
    217         builder.append(srcPath);
    218         builder.append(' ');
    219         builder.append(dstPath);
    220         return execute(builder.toString());
    221     }
    222 
    223     public int rmdex(String codePath) {
    224         StringBuilder builder = new StringBuilder("rmdex");
    225         builder.append(' ');
    226         builder.append(codePath);
    227         return execute(builder.toString());
    228     }
    229 
    230     public int remove(String name, int userId) {
    231         StringBuilder builder = new StringBuilder("remove");
    232         builder.append(' ');
    233         builder.append(name);
    234         builder.append(' ');
    235         builder.append(userId);
    236         return execute(builder.toString());
    237     }
    238 
    239     public int rename(String oldname, String newname) {
    240         StringBuilder builder = new StringBuilder("rename");
    241         builder.append(' ');
    242         builder.append(oldname);
    243         builder.append(' ');
    244         builder.append(newname);
    245         return execute(builder.toString());
    246     }
    247 
    248     public int fixUid(String name, int uid, int gid) {
    249         StringBuilder builder = new StringBuilder("fixuid");
    250         builder.append(' ');
    251         builder.append(name);
    252         builder.append(' ');
    253         builder.append(uid);
    254         builder.append(' ');
    255         builder.append(gid);
    256         return execute(builder.toString());
    257     }
    258 
    259     public int deleteCacheFiles(String name, int userId) {
    260         StringBuilder builder = new StringBuilder("rmcache");
    261         builder.append(' ');
    262         builder.append(name);
    263         builder.append(' ');
    264         builder.append(userId);
    265         return execute(builder.toString());
    266     }
    267 
    268     public int createUserData(String name, int uid, int userId) {
    269         StringBuilder builder = new StringBuilder("mkuserdata");
    270         builder.append(' ');
    271         builder.append(name);
    272         builder.append(' ');
    273         builder.append(uid);
    274         builder.append(' ');
    275         builder.append(userId);
    276         return execute(builder.toString());
    277     }
    278 
    279     public int removeUserDataDirs(int userId) {
    280         StringBuilder builder = new StringBuilder("rmuser");
    281         builder.append(' ');
    282         builder.append(userId);
    283         return execute(builder.toString());
    284     }
    285 
    286     public int clearUserData(String name, int userId) {
    287         StringBuilder builder = new StringBuilder("rmuserdata");
    288         builder.append(' ');
    289         builder.append(name);
    290         builder.append(' ');
    291         builder.append(userId);
    292         return execute(builder.toString());
    293     }
    294 
    295     public boolean ping() {
    296         if (execute("ping") < 0) {
    297             return false;
    298         } else {
    299             return true;
    300         }
    301     }
    302 
    303     public int freeCache(long freeStorageSize) {
    304         StringBuilder builder = new StringBuilder("freecache");
    305         builder.append(' ');
    306         builder.append(String.valueOf(freeStorageSize));
    307         return execute(builder.toString());
    308     }
    309 
    310     public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
    311             String fwdLockApkPath, String asecPath, PackageStats pStats) {
    312         StringBuilder builder = new StringBuilder("getsize");
    313         builder.append(' ');
    314         builder.append(pkgName);
    315         builder.append(' ');
    316         builder.append(persona);
    317         builder.append(' ');
    318         builder.append(apkPath);
    319         builder.append(' ');
    320         builder.append(libDirPath != null ? libDirPath : "!");
    321         builder.append(' ');
    322         builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
    323         builder.append(' ');
    324         builder.append(asecPath != null ? asecPath : "!");
    325 
    326         String s = transaction(builder.toString());
    327         String res[] = s.split(" ");
    328 
    329         if ((res == null) || (res.length != 5)) {
    330             return -1;
    331         }
    332         try {
    333             pStats.codeSize = Long.parseLong(res[1]);
    334             pStats.dataSize = Long.parseLong(res[2]);
    335             pStats.cacheSize = Long.parseLong(res[3]);
    336             pStats.externalCodeSize = Long.parseLong(res[4]);
    337             return Integer.parseInt(res[0]);
    338         } catch (NumberFormatException e) {
    339             return -1;
    340         }
    341     }
    342 
    343     public int moveFiles() {
    344         return execute("movefiles");
    345     }
    346 
    347     /**
    348      * Links the native library directory in an application's directory to its
    349      * real location.
    350      *
    351      * @param dataPath data directory where the application is
    352      * @param nativeLibPath target native library path
    353      * @return -1 on error
    354      */
    355     public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath, int userId) {
    356         if (dataPath == null) {
    357             Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
    358             return -1;
    359         } else if (nativeLibPath == null) {
    360             Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null");
    361             return -1;
    362         }
    363 
    364         StringBuilder builder = new StringBuilder("linklib ");
    365         builder.append(dataPath);
    366         builder.append(' ');
    367         builder.append(nativeLibPath);
    368         builder.append(' ');
    369         builder.append(userId);
    370 
    371         return execute(builder.toString());
    372     }
    373 }
    374