InstallerConnection.java revision 4e321745173de1eb89343238fadfbcc7ba1a88f9
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 17package com.android.internal.os; 18 19import android.net.LocalSocket; 20import android.net.LocalSocketAddress; 21import android.os.SystemClock; 22import android.util.Slog; 23import libcore.io.IoUtils; 24import libcore.io.Streams; 25 26import java.io.IOException; 27import java.io.InputStream; 28import java.io.OutputStream; 29 30/** 31 * Represents a connection to {@code installd}. Allows multiple connect and 32 * disconnect cycles. 33 * 34 * @hide for internal use only 35 */ 36public class InstallerConnection { 37 private static final String TAG = "InstallerConnection"; 38 private static final boolean LOCAL_DEBUG = false; 39 40 private InputStream mIn; 41 private OutputStream mOut; 42 private LocalSocket mSocket; 43 44 private final byte buf[] = new byte[1024]; 45 46 public InstallerConnection() { 47 } 48 49 public synchronized String transact(String cmd) { 50 if (!connect()) { 51 Slog.e(TAG, "connection failed"); 52 return "-1"; 53 } 54 55 if (!writeCommand(cmd)) { 56 /* 57 * If installd died and restarted in the background (unlikely but 58 * possible) we'll fail on the next write (this one). Try to 59 * reconnect and write the command one more time before giving up. 60 */ 61 Slog.e(TAG, "write command failed? reconnect!"); 62 if (!connect() || !writeCommand(cmd)) { 63 return "-1"; 64 } 65 } 66 if (LOCAL_DEBUG) { 67 Slog.i(TAG, "send: '" + cmd + "'"); 68 } 69 70 final int replyLength = readReply(); 71 if (replyLength > 0) { 72 String s = new String(buf, 0, replyLength); 73 if (LOCAL_DEBUG) { 74 Slog.i(TAG, "recv: '" + s + "'"); 75 } 76 return s; 77 } else { 78 if (LOCAL_DEBUG) { 79 Slog.i(TAG, "fail"); 80 } 81 return "-1"; 82 } 83 } 84 85 public int execute(String cmd) { 86 String res = transact(cmd); 87 try { 88 return Integer.parseInt(res); 89 } catch (NumberFormatException ex) { 90 return -1; 91 } 92 } 93 94 public int dexopt(String apkPath, int uid, boolean isPublic, 95 String instructionSet, int dexoptNeeded, boolean bootComplete) { 96 return dexopt(apkPath, uid, isPublic, "*", instructionSet, dexoptNeeded, 97 false, false, null, bootComplete); 98 } 99 100 public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, 101 String instructionSet, int dexoptNeeded, boolean vmSafeMode, 102 boolean debuggable, String outputPath, boolean bootComplete) { 103 StringBuilder builder = new StringBuilder("dexopt"); 104 builder.append(' '); 105 builder.append(apkPath); 106 builder.append(' '); 107 builder.append(uid); 108 builder.append(isPublic ? " 1" : " 0"); 109 builder.append(' '); 110 builder.append(pkgName); 111 builder.append(' '); 112 builder.append(instructionSet); 113 builder.append(' '); 114 builder.append(dexoptNeeded); 115 builder.append(vmSafeMode ? " 1" : " 0"); 116 builder.append(debuggable ? " 1" : " 0"); 117 builder.append(' '); 118 builder.append(outputPath != null ? outputPath : "!"); 119 builder.append(bootComplete ? " 1" : " 0"); 120 return execute(builder.toString()); 121 } 122 123 private boolean connect() { 124 if (mSocket != null) { 125 return true; 126 } 127 Slog.i(TAG, "connecting..."); 128 try { 129 mSocket = new LocalSocket(); 130 131 LocalSocketAddress address = new LocalSocketAddress("installd", 132 LocalSocketAddress.Namespace.RESERVED); 133 134 mSocket.connect(address); 135 136 mIn = mSocket.getInputStream(); 137 mOut = mSocket.getOutputStream(); 138 } catch (IOException ex) { 139 disconnect(); 140 return false; 141 } 142 return true; 143 } 144 145 public void disconnect() { 146 Slog.i(TAG, "disconnecting..."); 147 IoUtils.closeQuietly(mSocket); 148 IoUtils.closeQuietly(mIn); 149 IoUtils.closeQuietly(mOut); 150 151 mSocket = null; 152 mIn = null; 153 mOut = null; 154 } 155 156 157 private boolean readFully(byte[] buffer, int len) { 158 try { 159 Streams.readFully(mIn, buffer, 0, len); 160 } catch (IOException ioe) { 161 Slog.e(TAG, "read exception"); 162 disconnect(); 163 return false; 164 } 165 166 if (LOCAL_DEBUG) { 167 Slog.i(TAG, "read " + len + " bytes"); 168 } 169 170 return true; 171 } 172 173 private int readReply() { 174 if (!readFully(buf, 2)) { 175 return -1; 176 } 177 178 final int len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); 179 if ((len < 1) || (len > buf.length)) { 180 Slog.e(TAG, "invalid reply length (" + len + ")"); 181 disconnect(); 182 return -1; 183 } 184 185 if (!readFully(buf, len)) { 186 return -1; 187 } 188 189 return len; 190 } 191 192 private boolean writeCommand(String cmdString) { 193 final byte[] cmd = cmdString.getBytes(); 194 final int len = cmd.length; 195 if ((len < 1) || (len > buf.length)) { 196 return false; 197 } 198 199 buf[0] = (byte) (len & 0xff); 200 buf[1] = (byte) ((len >> 8) & 0xff); 201 try { 202 mOut.write(buf, 0, 2); 203 mOut.write(cmd, 0, len); 204 } catch (IOException ex) { 205 Slog.e(TAG, "write error"); 206 disconnect(); 207 return false; 208 } 209 return true; 210 } 211 212 public void waitForConnection() { 213 for (;;) { 214 if (execute("ping") >= 0) { 215 return; 216 } 217 Slog.w(TAG, "installd not ready"); 218 SystemClock.sleep(1000); 219 } 220 } 221} 222