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