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