/*
 * Copyright (C) 2019 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.
 */

#include "BinderIncrementalService.h"

#include <android-base/logging.h>
#include <android-base/no_destructor.h>
#include <android/os/IVold.h>
#include <binder/IResultReceiver.h>
#include <binder/PermissionCache.h>
#include <incfs.h>

#include "ServiceWrappers.h"
#include "jni.h"
#include "path.h"

using namespace std::literals;
using namespace android::incremental;

namespace android::os::incremental {

static constexpr auto kAndroidDataEnv = "ANDROID_DATA"sv;
static constexpr auto kDataDir = "/data"sv;
static constexpr auto kIncrementalSubDir = "incremental"sv;

static std::string getIncrementalDir() {
    const char* dataDir = getenv(kAndroidDataEnv.data());
    if (!dataDir || !*dataDir) {
        dataDir = kDataDir.data();
    }
    return path::normalize(path::join(dataDir, kIncrementalSubDir));
}

static bool incFsEnabled() {
    // TODO(b/136132412): use vold to check /sys/fs/incfs/version (per selinux compliance)
    return incfs::enabled();
}

static bool incFsValid(const sp<IVold>& vold) {
    bool enabled = false;
    auto status = vold->incFsEnabled(&enabled);
    if (!status.isOk() || !enabled) {
        return false;
    }
    return true;
}

BinderIncrementalService::BinderIncrementalService(const sp<IServiceManager>& sm, JNIEnv* env)
      : mImpl(RealServiceManager(sm, env), getIncrementalDir()) {}

BinderIncrementalService* BinderIncrementalService::start(JNIEnv* env) {
    if (!incFsEnabled()) {
        return nullptr;
    }

    IPCThreadState::self()->disableBackgroundScheduling(true);
    sp<IServiceManager> sm(defaultServiceManager());
    if (!sm) {
        return nullptr;
    }

    sp<IBinder> voldBinder(sm->getService(String16("vold")));
    if (voldBinder == nullptr) {
        return nullptr;
    }
    sp<IVold> vold = interface_cast<IVold>(voldBinder);
    if (!incFsValid(vold)) {
        return nullptr;
    }

    sp<BinderIncrementalService> self(new BinderIncrementalService(sm, env));
    status_t ret = sm->addService(String16{getServiceName()}, self);
    if (ret != android::OK) {
        return nullptr;
    }
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();
    ps->giveThreadPoolName();
    // sm->addService increments the reference count, and now we're OK with returning the pointer.
    return self.get();
}

status_t BinderIncrementalService::dump(int fd, const Vector<String16>&) {
    static const android::base::NoDestructor<String16> kDump("android.permission.DUMP");
    if (!PermissionCache::checkCallingPermission(*kDump)) {
        return PERMISSION_DENIED;
    }
    mImpl.onDump(fd);
    return NO_ERROR;
}

void BinderIncrementalService::onSystemReady() {
    mImpl.onSystemReady();
}

static binder::Status ok() {
    return binder::Status::ok();
}

binder::Status BinderIncrementalService::openStorage(const std::string& path,
                                                     int32_t* _aidl_return) {
    *_aidl_return = mImpl.openStorage(path);
    return ok();
}

binder::Status BinderIncrementalService::createStorage(
        const ::std::string& path, const ::android::content::pm::DataLoaderParamsParcel& params,
        int32_t createMode,
        const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& statusListener,
        const ::android::os::incremental::StorageHealthCheckParams& healthCheckParams,
        const ::android::sp<::android::os::incremental::IStorageHealthListener>& healthListener,
        int32_t* _aidl_return) {
    *_aidl_return =
            mImpl.createStorage(path, const_cast<content::pm::DataLoaderParamsParcel&&>(params),
                                android::incremental::IncrementalService::CreateOptions(createMode),
                                statusListener,
                                const_cast<StorageHealthCheckParams&&>(healthCheckParams),
                                healthListener);
    return ok();
}

binder::Status BinderIncrementalService::createLinkedStorage(const std::string& path,
                                                             int32_t otherStorageId,
                                                             int32_t createMode,
                                                             int32_t* _aidl_return) {
    *_aidl_return =
            mImpl.createLinkedStorage(path, otherStorageId,
                                      android::incremental::IncrementalService::CreateOptions(
                                              createMode));
    return ok();
}

binder::Status BinderIncrementalService::makeBindMount(int32_t storageId,
                                                       const std::string& sourcePath,
                                                       const std::string& targetFullPath,
                                                       int32_t bindType, int32_t* _aidl_return) {
    *_aidl_return = mImpl.bind(storageId, sourcePath, targetFullPath,
                               android::incremental::IncrementalService::BindKind(bindType));
    return ok();
}

binder::Status BinderIncrementalService::deleteBindMount(int32_t storageId,
                                                         const std::string& targetFullPath,
                                                         int32_t* _aidl_return) {
    *_aidl_return = mImpl.unbind(storageId, targetFullPath);
    return ok();
}

binder::Status BinderIncrementalService::deleteStorage(int32_t storageId) {
    mImpl.deleteStorage(storageId);
    return ok();
}

binder::Status BinderIncrementalService::disableReadLogs(int32_t storageId) {
    mImpl.disableReadLogs(storageId);
    return ok();
}

binder::Status BinderIncrementalService::makeDirectory(int32_t storageId, const std::string& path,
                                                       int32_t* _aidl_return) {
    *_aidl_return = mImpl.makeDir(storageId, path);
    return ok();
}

static std::tuple<int, incfs::FileId, incfs::NewFileParams> toMakeFileParams(
        const android::os::incremental::IncrementalNewFileParams& params) {
    incfs::FileId id;
    if (params.fileId.empty()) {
        if (params.metadata.empty()) {
            return {EINVAL, {}, {}};
        }
        id = IncrementalService::idFromMetadata(params.metadata);
    } else if (params.fileId.size() != sizeof(id)) {
        return {EINVAL, {}, {}};
    } else {
        memcpy(&id, params.fileId.data(), sizeof(id));
    }
    incfs::NewFileParams nfp;
    nfp.size = params.size;
    nfp.metadata = {(const char*)params.metadata.data(), (IncFsSize)params.metadata.size()};
    if (!params.signature) {
        nfp.signature = {};
    } else {
        nfp.signature = {(const char*)params.signature->data(),
                         (IncFsSize)params.signature->size()};
    }
    return {0, id, nfp};
}

binder::Status BinderIncrementalService::makeFile(
        int32_t storageId, const std::string& path,
        const ::android::os::incremental::IncrementalNewFileParams& params, int32_t* _aidl_return) {
    auto [err, fileId, nfp] = toMakeFileParams(params);
    if (err) {
        *_aidl_return = err;
        return ok();
    }

    *_aidl_return = mImpl.makeFile(storageId, path, 0777, fileId, nfp);
    return ok();
}
binder::Status BinderIncrementalService::makeFileFromRange(int32_t storageId,
                                                           const std::string& targetPath,
                                                           const std::string& sourcePath,
                                                           int64_t start, int64_t end,
                                                           int32_t* _aidl_return) {
    // TODO(b/136132412): implement this
    *_aidl_return = ENOSYS; // not implemented
    return ok();
}

binder::Status BinderIncrementalService::makeLink(int32_t sourceStorageId,
                                                  const std::string& sourcePath,
                                                  int32_t destStorageId,
                                                  const std::string& destPath,
                                                  int32_t* _aidl_return) {
    *_aidl_return = mImpl.link(sourceStorageId, sourcePath, destStorageId, destPath);
    return ok();
}

binder::Status BinderIncrementalService::unlink(int32_t storageId, const std::string& path,
                                                int32_t* _aidl_return) {
    *_aidl_return = mImpl.unlink(storageId, path);
    return ok();
}

binder::Status BinderIncrementalService::isFileRangeLoaded(int32_t storageId,
                                                           const std::string& path, int64_t start,
                                                           int64_t end, bool* _aidl_return) {
    // TODO: implement
    *_aidl_return = false;
    return ok();
}

binder::Status BinderIncrementalService::getMetadataByPath(int32_t storageId,
                                                           const std::string& path,
                                                           std::vector<uint8_t>* _aidl_return) {
    auto metadata = mImpl.getMetadata(storageId, path);
    _aidl_return->assign(metadata.begin(), metadata.end());
    return ok();
}

static FileId toFileId(const std::vector<uint8_t>& id) {
    FileId fid;
    memcpy(&fid, id.data(), id.size());
    return fid;
}

binder::Status BinderIncrementalService::getMetadataById(int32_t storageId,
                                                         const std::vector<uint8_t>& id,
                                                         std::vector<uint8_t>* _aidl_return) {
    if (id.size() != sizeof(incfs::FileId)) {
        return ok();
    }
    auto fid = toFileId(id);
    auto metadata = mImpl.getMetadata(storageId, fid);
    _aidl_return->assign(metadata.begin(), metadata.end());
    return ok();
}

binder::Status BinderIncrementalService::makeDirectories(int32_t storageId, const std::string& path,
                                                         int32_t* _aidl_return) {
    *_aidl_return = mImpl.makeDirs(storageId, path);
    return ok();
}

binder::Status BinderIncrementalService::startLoading(int32_t storageId, bool* _aidl_return) {
    *_aidl_return = mImpl.startLoading(storageId);
    return ok();
}

binder::Status BinderIncrementalService::configureNativeBinaries(
        int32_t storageId, const std::string& apkFullPath, const std::string& libDirRelativePath,
        const std::string& abi, bool extractNativeLibs, bool* _aidl_return) {
    *_aidl_return = mImpl.configureNativeBinaries(storageId, apkFullPath, libDirRelativePath, abi,
                                                  extractNativeLibs);
    return ok();
}

binder::Status BinderIncrementalService::waitForNativeBinariesExtraction(int storageId,
                                                                         bool* _aidl_return) {
    *_aidl_return = mImpl.waitForNativeBinariesExtraction(storageId);
    return ok();
}

} // namespace android::os::incremental

jlong Incremental_IncrementalService_Start(JNIEnv* env) {
    return (jlong)android::os::incremental::BinderIncrementalService::start(env);
}
void Incremental_IncrementalService_OnSystemReady(jlong self) {
    if (self) {
        ((android::os::incremental::BinderIncrementalService*)self)->onSystemReady();
    }
}
void Incremental_IncrementalService_OnDump(jlong self, jint fd) {
    if (self) {
        ((android::os::incremental::BinderIncrementalService*)self)->dump(fd, {});
    } else {
        dprintf(fd, "BinderIncrementalService is stopped.");
    }
}
