Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7797e545 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by android-build-merger
Browse files

Merge "Final push of installd to Binder; goodbye socket!" am: 1950377f am: 104fd011

am: 9ff67746

Change-Id: Idc2b65f975b80c4768280515bd35727644fb5711
parents cc3b7793 9ff67746
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -477,6 +477,7 @@ LOCAL_SRC_FILES += \

LOCAL_SRC_FILES +=  \
	../../system/netd/server/binder/android/net/INetd.aidl \
	../native/cmds/installd/binder/android/os/IInstalld.aidl \

LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings

+0 −285
Original line number Diff line number Diff line
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package com.android.internal.os;

import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Slog;

import com.android.internal.util.Preconditions;

import libcore.io.IoUtils;
import libcore.io.Streams;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;

/**
 * Represents a connection to {@code installd}. Allows multiple connect and
 * disconnect cycles.
 *
 * @hide for internal use only
 */
public class InstallerConnection {
    private static final String TAG = "InstallerConnection";
    private static final boolean LOCAL_DEBUG = false;

    private InputStream mIn;
    private OutputStream mOut;
    private LocalSocket mSocket;

    private volatile Object mWarnIfHeld;

    private final byte buf[] = new byte[1024];

    public InstallerConnection() {
    }

    /**
     * Yell loudly if someone tries making future calls while holding a lock on
     * the given object.
     */
    public void setWarnIfHeld(Object warnIfHeld) {
        Preconditions.checkState(mWarnIfHeld == null);
        mWarnIfHeld = Preconditions.checkNotNull(warnIfHeld);
    }

    public synchronized String transact(String cmd) {
        if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
            Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
                    + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
        }

        if (!connect()) {
            Slog.e(TAG, "connection failed");
            return "-1";
        }

        if (!writeCommand(cmd)) {
            /*
             * If installd died and restarted in the background (unlikely but
             * possible) we'll fail on the next write (this one). Try to
             * reconnect and write the command one more time before giving up.
             */
            Slog.e(TAG, "write command failed? reconnect!");
            if (!connect() || !writeCommand(cmd)) {
                return "-1";
            }
        }
        if (LOCAL_DEBUG) {
            Slog.i(TAG, "send: '" + cmd + "'");
        }

        final int replyLength = readReply();
        if (replyLength > 0) {
            String s = new String(buf, 0, replyLength);
            if (LOCAL_DEBUG) {
                Slog.i(TAG, "recv: '" + s + "'");
            }
            return s;
        } else {
            if (LOCAL_DEBUG) {
                Slog.i(TAG, "fail");
            }
            return "-1";
        }
    }

    public String[] execute(String cmd, Object... args) throws InstallerException {
        final StringBuilder builder = new StringBuilder(cmd);
        for (Object arg : args) {
            String escaped;
            if (arg == null) {
                escaped = "";
            } else {
                escaped = String.valueOf(arg);
            }
            if (escaped.indexOf('\0') != -1 || escaped.indexOf(' ') != -1 || "!".equals(escaped)) {
                throw new InstallerException(
                        "Invalid argument while executing " + cmd + " " + Arrays.toString(args));
            }
            if (TextUtils.isEmpty(escaped)) {
                escaped = "!";
            }
            builder.append(' ').append(escaped);
        }
        final String[] resRaw = transact(builder.toString()).split(" ");
        int res = -1;
        try {
            res = Integer.parseInt(resRaw[0]);
        } catch (ArrayIndexOutOfBoundsException | NumberFormatException ignored) {
        }
        if (res != 0) {
            throw new InstallerException(
                    "Failed to execute " + cmd + " " + Arrays.toString(args) + ": " + res);
        }
        return resRaw;
    }

    public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
            int dexoptNeeded, String outputPath, int dexFlags, String compilerFilter,
            String volumeUuid, String sharedLibraries) throws InstallerException {
        execute("dexopt",
                apkPath,
                uid,
                pkgName,
                instructionSet,
                dexoptNeeded,
                outputPath,
                dexFlags,
                compilerFilter,
                volumeUuid,
                sharedLibraries);
    }

    private boolean safeParseBooleanResult(String[] res) throws InstallerException {
        if ((res == null) || (res.length != 2)) {
            throw new InstallerException("Invalid size result: " + Arrays.toString(res));
        }

        // Just as a sanity check. Anything != "true" will be interpreted as false by parseBoolean.
        if (!res[1].equals("true") && !res[1].equals("false")) {
            throw new InstallerException("Invalid boolean result: " + Arrays.toString(res));
        }

        return Boolean.parseBoolean(res[1]);
    }

    public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
        final String[] res = execute("merge_profiles", uid, pkgName);

        return safeParseBooleanResult(res);
    }

    public boolean dumpProfiles(String gid, String packageName, String codePaths)
            throws InstallerException {
        final String[] res = execute("dump_profiles", gid, packageName, codePaths);

        return safeParseBooleanResult(res);
    }

    private boolean connect() {
        if (mSocket != null) {
            return true;
        }
        Slog.i(TAG, "connecting...");
        try {
            mSocket = new LocalSocket();

            LocalSocketAddress address = new LocalSocketAddress("installd",
                    LocalSocketAddress.Namespace.RESERVED);

            mSocket.connect(address);

            mIn = mSocket.getInputStream();
            mOut = mSocket.getOutputStream();
        } catch (IOException ex) {
            disconnect();
            return false;
        }
        return true;
    }

    public void disconnect() {
        Slog.i(TAG, "disconnecting...");
        IoUtils.closeQuietly(mSocket);
        IoUtils.closeQuietly(mIn);
        IoUtils.closeQuietly(mOut);

        mSocket = null;
        mIn = null;
        mOut = null;
    }


    private boolean readFully(byte[] buffer, int len) {
        try {
            Streams.readFully(mIn, buffer, 0, len);
        } catch (IOException ioe) {
            Slog.e(TAG, "read exception");
            disconnect();
            return false;
        }

        if (LOCAL_DEBUG) {
            Slog.i(TAG, "read " + len + " bytes");
        }

        return true;
    }

    private int readReply() {
        if (!readFully(buf, 2)) {
            return -1;
        }

        final int len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
        if ((len < 1) || (len > buf.length)) {
            Slog.e(TAG, "invalid reply length (" + len + ")");
            disconnect();
            return -1;
        }

        if (!readFully(buf, len)) {
            return -1;
        }

        return len;
    }

    private boolean writeCommand(String cmdString) {
        final byte[] cmd = cmdString.getBytes();
        final int len = cmd.length;
        if ((len < 1) || (len > buf.length)) {
            return false;
        }

        buf[0] = (byte) (len & 0xff);
        buf[1] = (byte) ((len >> 8) & 0xff);
        try {
            mOut.write(buf, 0, 2);
            mOut.write(cmd, 0, len);
        } catch (IOException ex) {
            Slog.e(TAG, "write error");
            disconnect();
            return false;
        }
        return true;
    }

    public void waitForConnection() {
        for (;;) {
            try {
                execute("ping");
                return;
            } catch (InstallerException ignored) {
            }
            Slog.w(TAG, "installd not ready");
            SystemClock.sleep(1000);
        }
    }

    public static class InstallerException extends Exception {
        public InstallerException(String detailMessage) {
            super(detailMessage);
        }
    }
}
+45 −46
Original line number Diff line number Diff line
@@ -26,7 +26,11 @@ import android.icu.text.DecimalFormatSymbols;
import android.icu.util.ULocale;
import android.net.LocalServerSocket;
import android.opengl.EGL14;
import android.os.IInstalld;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
@@ -42,7 +46,6 @@ import android.util.Log;
import android.webkit.WebViewFactory;
import android.widget.TextView;

import com.android.internal.os.InstallerConnection.InstallerException;

import dalvik.system.DexFile;
import dalvik.system.PathClassLoader;
@@ -493,11 +496,10 @@ public class ZygoteInit {
     */
    private static void performSystemServerDexOpt(String classPath) {
        final String[] classPathElements = classPath.split(":");
        final InstallerConnection installer = new InstallerConnection();
        installer.waitForConnection();
        final IInstalld installd = IInstalld.Stub
                .asInterface(ServiceManager.getService("installd"));
        final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();

        try {
        String sharedLibraries = "";
        for (String classPathElement : classPathElements) {
            // System server is fully AOTed and never profiled
@@ -529,10 +531,10 @@ public class ZygoteInit {
                final String compilerFilter = "speed";
                final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
                try {
                        installer.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
                    installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
                            instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
                            uuid, sharedLibraries);
                    } catch (InstallerException e) {
                } catch (RemoteException | ServiceSpecificException e) {
                    // Ignore (but log), we need this on the classpath for fallback mode.
                    Log.w(TAG, "Failed compiling classpath element for system server: "
                            + classPathElement, e);
@@ -544,9 +546,6 @@ public class ZygoteInit {
            }
            sharedLibraries += classPathElement;
        }
        } finally {
            installer.disconnect();
        }
    }

    /**
+1 −1
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import com.android.internal.os.IResultReceiver;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TransferPipe;
import com.android.internal.os.Zygote;
import com.android.internal.os.InstallerConnection.InstallerException;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
@@ -54,6 +53,7 @@ import com.android.server.Watchdog;
import com.android.server.am.ActivityStack.ActivityState;
import com.android.server.firewall.IntentFirewall;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.vr.VrManagerInternal;
import com.android.server.wm.WindowManagerService;
+52 −53
Original line number Diff line number Diff line
@@ -26,14 +26,10 @@ import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.util.Slog;

import com.android.internal.os.InstallerConnection;
import com.android.internal.os.InstallerConnection.InstallerException;
import com.android.server.SystemService;

import dalvik.system.VMRuntime;

import java.util.Arrays;

public class Installer extends SystemService {
    private static final String TAG = "Installer";

@@ -61,9 +57,7 @@ public class Installer extends SystemService {
    private final boolean mIsolated;

    // TODO: reconnect if installd restarts
    private final InstallerConnection mInstaller;
    private final IInstalld mInstalld;

    private volatile IInstalld mInstalld;
    private volatile Object mWarnIfHeld;

    public Installer(Context context) {
@@ -78,13 +72,6 @@ public class Installer extends SystemService {
    public Installer(Context context, boolean isolated) {
        super(context);
        mIsolated = isolated;
        if (isolated) {
            mInstaller = null;
            mInstalld = null;
        } else {
            mInstaller = new InstallerConnection();
            mInstalld = IInstalld.Stub.asInterface(ServiceManager.getService("installd"));
        }
    }

    /**
@@ -92,17 +79,15 @@ public class Installer extends SystemService {
     * the given object.
     */
    public void setWarnIfHeld(Object warnIfHeld) {
        if (mInstaller != null) {
            mInstaller.setWarnIfHeld(warnIfHeld);
        }
        mWarnIfHeld = warnIfHeld;
    }

    @Override
    public void onStart() {
        if (mInstaller != null) {
            Slog.i(TAG, "Waiting for installd to be ready.");
            mInstaller.waitForConnection();
        if (mIsolated) {
            mInstalld = null;
        } else {
            mInstalld = IInstalld.Stub.asInterface(ServiceManager.getService("installd"));
        }
    }

@@ -131,7 +116,7 @@ public class Installer extends SystemService {
            mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
                    targetSdkVersion);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -141,7 +126,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.restoreconAppData(uuid, packageName, userId, flags, appId, seInfo);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -151,7 +136,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.migrateAppData(uuid, packageName, userId, flags);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -161,7 +146,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.clearAppData(uuid, packageName, userId, flags, ceDataInode);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -171,7 +156,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -183,21 +168,21 @@ public class Installer extends SystemService {
            mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, dataAppName, appId, seInfo,
                    targetSdkVersion);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

    public void getAppSize(String uuid, String pkgname, int userid, int flags, long ceDataInode,
    public void getAppSize(String uuid, String packageName, int userId, int flags, long ceDataInode,
            String codePath, PackageStats stats) throws InstallerException {
        if (!checkBeforeRemote()) return;
        final String[] res = mInstaller.execute("get_app_size", uuid, pkgname, userid, flags,
                ceDataInode, codePath);
        try {
            stats.codeSize += Long.parseLong(res[1]);
            stats.dataSize += Long.parseLong(res[2]);
            stats.cacheSize += Long.parseLong(res[3]);
        } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
            throw new InstallerException("Invalid size result: " + Arrays.toString(res));
            final long[] res = mInstalld.getAppSize(uuid, packageName, userId, flags, ceDataInode,
                    codePath);
            stats.codeSize += res[0];
            stats.dataSize += res[1];
            stats.cacheSize += res[2];
        } catch (RemoteException | ServiceSpecificException e) {
            throw InstallerException.from(e);
        }
    }

@@ -207,7 +192,7 @@ public class Installer extends SystemService {
        try {
            return mInstalld.getAppDataInode(uuid, packageName, userId, flags);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -217,8 +202,12 @@ public class Installer extends SystemService {
            throws InstallerException {
        assertValidInstructionSet(instructionSet);
        if (!checkBeforeRemote()) return;
        mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
                outputPath, dexFlags, compilerFilter, volumeUuid, sharedLibraries);
        try {
            mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
                    dexFlags, compilerFilter, volumeUuid, sharedLibraries);
        } catch (RemoteException | ServiceSpecificException e) {
            throw InstallerException.from(e);
        }
    }

    public boolean mergeProfiles(int uid, String packageName) throws InstallerException {
@@ -226,7 +215,7 @@ public class Installer extends SystemService {
        try {
            return mInstalld.mergeProfiles(uid, packageName);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -236,7 +225,7 @@ public class Installer extends SystemService {
        try {
            return mInstalld.dumpProfiles(uid, packageName, codePaths);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -246,7 +235,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.idmap(targetApkPath, overlayApkPath, uid);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -256,7 +245,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.rmdex(codePath, instructionSet);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -265,7 +254,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.rmPackageDir(packageDir);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -274,7 +263,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.clearAppProfiles(packageName);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -283,7 +272,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.destroyAppProfiles(packageName);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -293,7 +282,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.createUserData(uuid, userId, userSerial, flags);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -302,7 +291,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.destroyUserData(uuid, userId, flags);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -312,7 +301,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.markBootComplete(instructionSet);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -321,7 +310,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.freeCache(uuid, freeStorageSize);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -336,7 +325,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -346,7 +335,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.createOatDir(oatDir, dexInstructionSet);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -356,7 +345,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.linkFile(relativePath, fromBase, toBase);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -366,7 +355,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.moveAb(apkPath, instructionSet, outputPath);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -376,7 +365,7 @@ public class Installer extends SystemService {
        try {
            mInstalld.deleteOdex(apkPath, instructionSet, outputPath);
        } catch (RemoteException | ServiceSpecificException e) {
            throw new InstallerException(e.getMessage());
            throw InstallerException.from(e);
        }
    }

@@ -389,4 +378,14 @@ public class Installer extends SystemService {
        }
        throw new InstallerException("Invalid instruction set: " + instructionSet);
    }

    public static class InstallerException extends Exception {
        public InstallerException(String detailMessage) {
            super(detailMessage);
        }

        public static InstallerException from(Exception e) throws InstallerException {
            throw new InstallerException(e.getMessage());
        }
    }
}
Loading