Initial Binder interface for installd.

Define an AIDL for installd, starting with a single method.  Publish
that interface for the system to start using.  We'll circle back and
migrate more methods in future CLs.

Migrating installd to Binder will allow us to get rid of one of
the few lingering text-based command protocols, improving system
maintainability and security.

Test: builds, boots
Bug: 13758960, 30944031
Change-Id: Icdb5320082567e0355d8f76f413f01cfacf0fb99
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 17886fa..6487d84 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -80,13 +80,19 @@
 LOCAL_MODULE := installd
 LOCAL_MODULE_TAGS := optional
 LOCAL_CFLAGS := $(common_cflags)
-LOCAL_SRC_FILES := installd.cpp $(common_src_files)
+LOCAL_SRC_FILES := $(common_src_files) \
+    installd.cpp \
+    InstalldNativeService.cpp \
+    binder/android/os/IInstalld.aidl \
+
 LOCAL_SHARED_LIBRARIES := \
     libbase \
+    libbinder \
     libcutils \
     liblog \
     liblogwrap \
     libselinux \
+    libutils
 
 LOCAL_STATIC_LIBRARIES := libdiskusage
 LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
new file mode 100644
index 0000000..d68035f
--- /dev/null
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
+
+#define LOG_TAG "installd"
+
+#include <vector>
+#include <fstream>
+
+#include <android-base/stringprintf.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Errors.h>
+#include <utils/String16.h>
+
+#include "InstalldNativeService.h"
+
+#include "commands.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+namespace {
+
+constexpr const char* kDump = "android.permission.DUMP";
+
+binder::Status checkPermission(const char* permission) {
+    pid_t pid;
+    uid_t uid;
+
+    if (checkCallingPermission(String16(permission), reinterpret_cast<int32_t*>(&pid),
+            reinterpret_cast<int32_t*>(&uid))) {
+        return binder::Status::ok();
+    } else {
+        auto err = StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission);
+        return binder::Status::fromExceptionCode(binder::Status::EX_SECURITY, String8(err.c_str()));
+    }
+}
+
+binder::Status checkUid(uid_t expectedUid) {
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    if (uid == expectedUid) {
+        return binder::Status::ok();
+    } else {
+        auto err = StringPrintf("UID %d is not expected UID %d", uid, expectedUid);
+        return binder::Status::fromExceptionCode(binder::Status::EX_SECURITY, String8(err.c_str()));
+    }
+}
+
+#define ENFORCE_UID(uid) {                                  \
+    binder::Status status = checkUid((uid));                \
+    if (!status.isOk()) {                                   \
+        return status;                                      \
+    }                                                       \
+}
+
+}  // namespace
+
+status_t InstalldNativeService::start() {
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+    status_t ret = BinderService<InstalldNativeService>::publish();
+    if (ret != android::OK) {
+        return ret;
+    }
+    sp<ProcessState> ps(ProcessState::self());
+    ps->startThreadPool();
+    ps->giveThreadPoolName();
+    return android::OK;
+}
+
+status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) {
+    const binder::Status dump_permission = checkPermission(kDump);
+    if (!dump_permission.isOk()) {
+        const String8 msg(dump_permission.toString8());
+        write(fd, msg.string(), msg.size());
+        return PERMISSION_DENIED;
+    }
+
+    std::string msg = "installd is happy\n";
+    write(fd, msg.c_str(), strlen(msg.c_str()));
+    return NO_ERROR;
+}
+
+static binder::Status translateStatus(int ret) {
+    if (ret != 0) {
+        auto err = StringPrintf("Failed with error %d", ret);
+        return binder::Status::fromServiceSpecificError(ret, String8(err.c_str()));
+    } else {
+        return binder::Status::ok();
+    }
+}
+
+binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
+        const std::string& pkgname, int32_t userid, int32_t flags, int32_t appid,
+        const std::string& seinfo, int32_t targetSdkVersion) {
+    ENFORCE_UID(AID_SYSTEM);
+    const char* _uuid = uuid ? (*uuid).c_str() : nullptr;
+    return translateStatus(create_app_data(_uuid, pkgname.c_str(), userid, flags, appid,
+            seinfo.c_str(), targetSdkVersion));
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
new file mode 100644
index 0000000..64973bf
--- /dev/null
+++ b/cmds/installd/InstalldNativeService.h
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
+
+#ifndef _INSTALLD_NATIVE_SERVICE_H_
+#define _INSTALLD_NATIVE_SERVICE_H_
+
+#include <vector>
+
+#include <binder/BinderService.h>
+
+#include "android/os/BnInstalld.h"
+
+namespace android {
+namespace installd {
+
+class InstalldNativeService : public BinderService<InstalldNativeService>, public os::BnInstalld {
+  public:
+    static status_t start();
+    static char const* getServiceName() { return "installd"; }
+    virtual status_t dump(int fd, const Vector<String16> &args) override;
+
+    binder::Status createAppData(const std::unique_ptr<std::string>& uuid,
+            const std::string& pkgname, int32_t userid, int32_t flags, int32_t appid,
+            const std::string& seinfo, int32_t targetSdkVersion);
+};
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // _INSTALLD_NATIVE_SERVICE_H_
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
new file mode 100644
index 0000000..5e36244
--- /dev/null
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 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 android.os;
+
+interface IInstalld {
+    void createAppData(in @nullable @utf8InCpp String uuid, in @utf8InCpp String pkgname,
+            int userid, int flags, int appid, in @utf8InCpp String seinfo, int targetSdkVersion);
+}
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index c81a339..332bc5e 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -30,6 +30,8 @@
 #include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
 
+#include <InstalldNativeService.h>
+
 #include <commands.h>
 #include <globals.h>
 #include <installd_constants.h>
@@ -705,7 +707,7 @@
     char buf[BUFFER_MAX];
     struct sockaddr addr;
     socklen_t alen;
-    int lsocket, s;
+    int lsocket, s, ret;
     int selinux_enabled = (is_selinux_enabled() > 0);
 
     setenv("ANDROID_LOG_TAGS", "*:v", 1);
@@ -732,6 +734,11 @@
         exit(1);
     }
 
+    if ((ret = InstalldNativeService::start()) != android::OK) {
+        ALOGE("Unable to start InstalldNativeService: %d", ret);
+        exit(1);
+    }
+
     lsocket = android_get_control_socket(SOCKET_PATH);
     if (lsocket < 0) {
         ALOGE("Failed to get socket from environment: %s\n", strerror(errno));