/*
 * Copyright (C) 2015 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_NDEBUG 0
#define LOG_TAG "ProcessInfo"
#include <utils/Log.h>

#include <media/stagefright/ProcessInfo.h>

#include <binder/IPCThreadState.h>
#include <binder/IProcessInfoService.h>
#include <binder/IServiceManager.h>
#include <private/android_filesystem_config.h>

namespace android {

static constexpr int32_t INVALID_ADJ = -10000;
static constexpr int32_t NATIVE_ADJ = -1000;

ProcessInfo::ProcessInfo() {}

bool ProcessInfo::getPriority(int pid, int* priority) {
    sp<IBinder> binder = defaultServiceManager()->getService(String16("processinfo"));
    sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);

    size_t length = 1;
    int32_t state;
    int32_t score = INVALID_ADJ;
    status_t err = service->getProcessStatesAndOomScoresFromPids(length, &pid, &state, &score);
    if (err != OK) {
        ALOGE("getProcessStatesAndOomScoresFromPids failed");
        return false;
    }
    ALOGV("pid %d state %d score %d", pid, state, score);
    if (score <= NATIVE_ADJ) {
        std::scoped_lock lock{mOverrideLock};

        // If this process if not tracked by ActivityManagerService, look for overrides.
        auto it = mOverrideMap.find(pid);
        if (it != mOverrideMap.end()) {
            ALOGI("pid %d invalid OOM score %d, override to %d", pid, score, it->second.oomScore);
            score = it->second.oomScore;
        } else {
            ALOGE("pid %d invalid OOM score %d", pid, score);
            return false;
        }
    }

    // Use OOM adjustments value as the priority. Lower the value, higher the priority.
    *priority = score;
    return true;
}

bool ProcessInfo::isValidPid(int pid) {
    int callingPid = IPCThreadState::self()->getCallingPid();
    int callingUid = IPCThreadState::self()->getCallingUid();
    // Trust it if this is called from the same process otherwise pid has to match the calling pid.
    return (callingPid == getpid()) || (callingPid == pid) || (callingUid == AID_MEDIA);
}

bool ProcessInfo::overrideProcessInfo(int pid, int procState, int oomScore) {
    std::scoped_lock lock{mOverrideLock};

    mOverrideMap.erase(pid);

    // Disable the override if oomScore is set to NATIVE_ADJ or below.
    if (oomScore <= NATIVE_ADJ) {
        return false;
    }

    mOverrideMap.emplace(pid, ProcessInfoOverride{procState, oomScore});
    return true;
}

void ProcessInfo::removeProcessInfoOverride(int pid) {
    std::scoped_lock lock{mOverrideLock};

    mOverrideMap.erase(pid);
}

ProcessInfo::~ProcessInfo() {}

}  // namespace android
