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) { 96 return dexopt(apkPath, uid, isPublic, "*", instructionSet, dexoptNeeded, 97 false, false, null); 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) { 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 return execute(builder.toString()); 120 } 121 122 private boolean connect() { 123 if (mSocket != null) { 124 return true; 125 } 126 Slog.i(TAG, "connecting..."); 127 try { 128 mSocket = new LocalSocket(); 129 130 LocalSocketAddress address = new LocalSocketAddress("installd", 131 LocalSocketAddress.Namespace.RESERVED); 132 133 mSocket.connect(address); 134 135 mIn = mSocket.getInputStream(); 136 mOut = mSocket.getOutputStream(); 137 } catch (IOException ex) { 138 disconnect(); 139 return false; 140 } 141 return true; 142 } 143 144 public void disconnect() { 145 Slog.i(TAG, "disconnecting..."); 146 IoUtils.closeQuietly(mSocket); 147 IoUtils.closeQuietly(mIn); 148 IoUtils.closeQuietly(mOut); 149 150 mSocket = null; 151 mIn = null; 152 mOut = null; 153 } 154 155 156 private boolean readFully(byte[] buffer, int len) { 157 try { 158 Streams.readFully(mIn, buffer, 0, len); 159 } catch (IOException ioe) { 160 Slog.e(TAG, "read exception"); 161 disconnect(); 162 return false; 163 } 164 165 if (LOCAL_DEBUG) { 166 Slog.i(TAG, "read " + len + " bytes"); 167 } 168 169 return true; 170 } 171 172 private int readReply() { 173 if (!readFully(buf, 2)) { 174 return -1; 175 } 176 177 final int len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); 178 if ((len < 1) || (len > buf.length)) { 179 Slog.e(TAG, "invalid reply length (" + len + ")"); 180 disconnect(); 181 return -1; 182 } 183 184 if (!readFully(buf, len)) { 185 return -1; 186 } 187 188 return len; 189 } 190 191 private boolean writeCommand(String cmdString) { 192 final byte[] cmd = cmdString.getBytes(); 193 final int len = cmd.length; 194 if ((len < 1) || (len > buf.length)) { 195 return false; 196 } 197 198 buf[0] = (byte) (len & 0xff); 199 buf[1] = (byte) ((len >> 8) & 0xff); 200 try { 201 mOut.write(buf, 0, 2); 202 mOut.write(cmd, 0, len); 203 } catch (IOException ex) { 204 Slog.e(TAG, "write error"); 205 disconnect(); 206 return false; 207 } 208 return true; 209 } 210 211 public void waitForConnection() { 212 for (;;) { 213 if (execute("ping") >= 0) { 214 return; 215 } 216 Slog.w(TAG, "installd not ready"); 217 SystemClock.sleep(1000); 218 } 219 } 220} 221