/*
 * Copyright (C) 2018 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 "src/traced/probes/filesystem/inode_file_data_source.h"

#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <queue>
#include <unordered_map>

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/tracing/core/trace_packet.h"
#include "perfetto/ext/tracing/core/trace_writer.h"

#include "protos/perfetto/config/inode_file/inode_file_config.pbzero.h"
#include "protos/perfetto/trace/filesystem/inode_file_map.pbzero.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
#include "src/traced/probes/filesystem/file_scanner.h"

namespace perfetto {
namespace {
constexpr uint32_t kScanIntervalMs = 10000;  // 10s
constexpr uint32_t kScanDelayMs = 10000;     // 10s
constexpr uint32_t kScanBatchSize = 15000;

uint32_t OrDefault(uint32_t value, uint32_t def) {
  return value ? value : def;
}

std::string DbgFmt(const std::vector<std::string>& values) {
  if (values.empty())
    return "";

  std::string result;
  for (auto it = values.cbegin(); it != values.cend() - 1; ++it)
    result += *it + ",";

  result += values.back();
  return result;
}

class StaticMapDelegate : public FileScanner::Delegate {
 public:
  StaticMapDelegate(
      std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>* map)
      : map_(map) {}
  ~StaticMapDelegate() override {}

 private:
  bool OnInodeFound(BlockDeviceID block_device_id,
                    Inode inode_number,
                    const std::string& path,
                    InodeFileMap_Entry_Type type) override {
    std::unordered_map<Inode, InodeMapValue>& inode_map =
        (*map_)[block_device_id];
    inode_map[inode_number].SetType(type);
    inode_map[inode_number].AddPath(path);
    return true;
  }
  void OnInodeScanDone() override {}
  std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>* map_;
};

}  // namespace

// static
const ProbesDataSource::Descriptor InodeFileDataSource::descriptor = {
    /*name*/ "linux.inode_file_map",
    /*flags*/ Descriptor::kFlagsNone,
    /*fill_descriptor_func*/ nullptr,
};

void CreateStaticDeviceToInodeMap(
    const std::string& root_directory,
    std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>*
        static_file_map) {
  StaticMapDelegate delegate(static_file_map);
  FileScanner scanner({root_directory}, &delegate);
  scanner.Scan();
}

void InodeFileDataSource::FillInodeEntry(InodeFileMap* destination,
                                         Inode inode_number,
                                         const InodeMapValue& inode_map_value) {
  auto* entry = destination->add_entries();
  entry->set_inode_number(inode_number);
  entry->set_type(static_cast<protos::pbzero::InodeFileMap_Entry_Type>(
      inode_map_value.type()));
  for (const auto& path : inode_map_value.paths())
    entry->add_paths(path.c_str());
}

InodeFileDataSource::InodeFileDataSource(
    const DataSourceConfig& ds_config,
    base::TaskRunner* task_runner,
    TracingSessionID session_id,
    std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>*
        static_file_map,
    LRUInodeCache* cache,
    std::unique_ptr<TraceWriter> writer)
    : ProbesDataSource(session_id, &descriptor),
      task_runner_(task_runner),
      static_file_map_(static_file_map),
      cache_(cache),
      writer_(std::move(writer)),
      weak_factory_(this) {
  using protos::pbzero::InodeFileConfig;
  InodeFileConfig::Decoder cfg(ds_config.inode_file_config_raw());
  for (auto mp = cfg.scan_mount_points(); mp; ++mp)
    scan_mount_points_.insert((*mp).ToStdString());
  for (auto mpm = cfg.mount_point_mapping(); mpm; ++mpm) {
    InodeFileConfig::MountPointMappingEntry::Decoder entry(*mpm);
    std::vector<std::string> scan_roots;
    for (auto scan_root = entry.scan_roots(); scan_root; ++scan_root)
      scan_roots.push_back((*scan_root).ToStdString());
    std::string mountpoint = entry.mountpoint().ToStdString();
    mount_point_mapping_.emplace(mountpoint, std::move(scan_roots));
  }
  scan_interval_ms_ = OrDefault(cfg.scan_interval_ms(), kScanIntervalMs);
  scan_delay_ms_ = OrDefault(cfg.scan_delay_ms(), kScanDelayMs);
  scan_batch_size_ = OrDefault(cfg.scan_batch_size(), kScanBatchSize);
  do_not_scan_ = cfg.do_not_scan();
}

InodeFileDataSource::~InodeFileDataSource() = default;

void InodeFileDataSource::Start() {
  // Nothing special to do, this data source is only reacting to on-demand
  // events such as OnInodes().
}

void InodeFileDataSource::AddInodesFromStaticMap(
    BlockDeviceID block_device_id,
    std::set<Inode>* inode_numbers) {
  // Check if block device id exists in static file map
  auto static_map_entry = static_file_map_->find(block_device_id);
  if (static_map_entry == static_file_map_->end())
    return;

  uint64_t system_found_count = 0;
  for (auto it = inode_numbers->begin(); it != inode_numbers->end();) {
    Inode inode_number = *it;
    // Check if inode number exists in static file map for given block device id
    auto inode_it = static_map_entry->second.find(inode_number);
    if (inode_it == static_map_entry->second.end()) {
      ++it;
      continue;
    }
    system_found_count++;
    it = inode_numbers->erase(it);
    FillInodeEntry(AddToCurrentTracePacket(block_device_id), inode_number,
                   inode_it->second);
  }
  PERFETTO_DLOG("%" PRIu64 " inodes found in static file map",
                system_found_count);
}

void InodeFileDataSource::AddInodesFromLRUCache(
    BlockDeviceID block_device_id,
    std::set<Inode>* inode_numbers) {
  uint64_t cache_found_count = 0;
  for (auto it = inode_numbers->begin(); it != inode_numbers->end();) {
    Inode inode_number = *it;
    auto value = cache_->Get(std::make_pair(block_device_id, inode_number));
    if (value == nullptr) {
      ++it;
      continue;
    }
    cache_found_count++;
    it = inode_numbers->erase(it);
    FillInodeEntry(AddToCurrentTracePacket(block_device_id), inode_number,
                   *value);
  }
  if (cache_found_count > 0)
    PERFETTO_DLOG("%" PRIu64 " inodes found in cache", cache_found_count);
}

void InodeFileDataSource::Flush(FlushRequestID,
                                std::function<void()> callback) {
  ResetTracePacket();
  writer_->Flush(callback);
}

void InodeFileDataSource::OnInodes(
    const base::FlatSet<InodeBlockPair>& inodes) {
  if (mount_points_.empty()) {
    mount_points_ = ParseMounts();
  }
  // Group inodes from FtraceMetadata by block device
  std::map<BlockDeviceID, std::set<Inode>> inode_file_maps;
  for (const auto& inodes_pair : inodes) {
    Inode inode_number = inodes_pair.first;
    BlockDeviceID block_device_id = inodes_pair.second;
    inode_file_maps[block_device_id].emplace(inode_number);
  }
  if (inode_file_maps.size() > 1)
    PERFETTO_DLOG("Saw %zu block devices.", inode_file_maps.size());

  // Write a TracePacket with an InodeFileMap proto for each block device id
  for (auto& inode_file_map_data : inode_file_maps) {
    BlockDeviceID block_device_id = inode_file_map_data.first;
    std::set<Inode>& inode_numbers = inode_file_map_data.second;
    PERFETTO_DLOG("Saw %zu unique inode numbers.", inode_numbers.size());

    // Add entries to InodeFileMap as inodes are found and resolved to their
    // paths/type
    AddInodesFromStaticMap(block_device_id, &inode_numbers);
    AddInodesFromLRUCache(block_device_id, &inode_numbers);

    if (do_not_scan_)
      inode_numbers.clear();

    // If we defined mount points we want to scan in the config,
    // skip inodes on other mount points.
    if (!scan_mount_points_.empty()) {
      bool process = true;
      auto range = mount_points_.equal_range(block_device_id);
      for (auto it = range.first; it != range.second; ++it) {
        if (scan_mount_points_.count(it->second) == 0) {
          process = false;
          break;
        }
      }
      if (!process)
        continue;
    }

    if (!inode_numbers.empty()) {
      // Try to piggy back the current scan.
      auto it = missing_inodes_.find(block_device_id);
      if (it != missing_inodes_.end()) {
        it->second.insert(inode_numbers.cbegin(), inode_numbers.cend());
      }
      next_missing_inodes_[block_device_id].insert(inode_numbers.cbegin(),
                                                   inode_numbers.cend());
      if (!scan_running_) {
        scan_running_ = true;
        auto weak_this = GetWeakPtr();
        task_runner_->PostDelayedTask(
            [weak_this] {
              if (!weak_this) {
                PERFETTO_DLOG("Giving up filesystem scan.");
                return;
              }
              weak_this->FindMissingInodes();
            },
            scan_delay_ms_);
      }
    }
  }
}

InodeFileMap* InodeFileDataSource::AddToCurrentTracePacket(
    BlockDeviceID block_device_id) {
  seen_block_devices_.emplace(block_device_id);
  if (!has_current_trace_packet_ ||
      current_block_device_id_ != block_device_id) {
    if (has_current_trace_packet_)
      current_trace_packet_->Finalize();
    current_trace_packet_ = writer_->NewTracePacket();
    current_file_map_ = current_trace_packet_->set_inode_file_map();
    has_current_trace_packet_ = true;

    // Add block device id to InodeFileMap
    current_file_map_->set_block_device_id(
        static_cast<uint64_t>(block_device_id));
    // Add mount points to InodeFileMap
    auto range = mount_points_.equal_range(block_device_id);
    for (std::multimap<BlockDeviceID, std::string>::iterator it = range.first;
         it != range.second; ++it)
      current_file_map_->add_mount_points(it->second.c_str());
  }
  return current_file_map_;
}

void InodeFileDataSource::RemoveFromNextMissingInodes(
    BlockDeviceID block_device_id,
    Inode inode_number) {
  auto it = next_missing_inodes_.find(block_device_id);
  if (it == next_missing_inodes_.end())
    return;
  it->second.erase(inode_number);
}

bool InodeFileDataSource::OnInodeFound(BlockDeviceID block_device_id,
                                       Inode inode_number,
                                       const std::string& path,
                                       InodeFileMap_Entry_Type inode_type) {
  auto it = missing_inodes_.find(block_device_id);
  if (it == missing_inodes_.end())
    return true;

  size_t n = it->second.erase(inode_number);
  if (n == 0)
    return true;

  if (it->second.empty())
    missing_inodes_.erase(it);

  RemoveFromNextMissingInodes(block_device_id, inode_number);

  std::pair<BlockDeviceID, Inode> key{block_device_id, inode_number};
  auto cur_val = cache_->Get(key);
  if (cur_val) {
    cur_val->AddPath(path);
    FillInodeEntry(AddToCurrentTracePacket(block_device_id), inode_number,
                   *cur_val);
  } else {
    InodeMapValue new_val(InodeMapValue(inode_type, {path}));
    cache_->Insert(key, new_val);
    FillInodeEntry(AddToCurrentTracePacket(block_device_id), inode_number,
                   new_val);
  }
  PERFETTO_DLOG("Filled %s", path.c_str());
  return !missing_inodes_.empty();
}

void InodeFileDataSource::ResetTracePacket() {
  current_block_device_id_ = 0;
  current_file_map_ = nullptr;
  if (has_current_trace_packet_)
    current_trace_packet_->Finalize();
  has_current_trace_packet_ = false;
}

void InodeFileDataSource::OnInodeScanDone() {
  // Finalize the accumulated trace packets.
  ResetTracePacket();
  file_scanner_.reset();
  if (!missing_inodes_.empty()) {
    // At least write mount point mapping for inodes that are not found.
    for (const auto& p : missing_inodes_) {
      if (seen_block_devices_.count(p.first) == 0)
        AddToCurrentTracePacket(p.first);
    }
  }

  if (next_missing_inodes_.empty()) {
    scan_running_ = false;
  } else {
    auto weak_this = GetWeakPtr();
    PERFETTO_DLOG("Starting another filesystem scan.");
    task_runner_->PostDelayedTask(
        [weak_this] {
          if (!weak_this) {
            PERFETTO_DLOG("Giving up filesystem scan.");
            return;
          }
          weak_this->FindMissingInodes();
        },
        scan_delay_ms_);
  }
}

void InodeFileDataSource::AddRootsForBlockDevice(
    BlockDeviceID block_device_id,
    std::vector<std::string>* roots) {
  auto range = mount_points_.equal_range(block_device_id);
  for (auto it = range.first; it != range.second; ++it) {
    PERFETTO_DLOG("Trying to replace %s", it->second.c_str());
    auto replace_it = mount_point_mapping_.find(it->second);
    if (replace_it != mount_point_mapping_.end()) {
      roots->insert(roots->end(), replace_it->second.cbegin(),
                    replace_it->second.cend());
      return;
    }
  }

  for (auto it = range.first; it != range.second; ++it)
    roots->emplace_back(it->second);
}

void InodeFileDataSource::FindMissingInodes() {
  missing_inodes_ = std::move(next_missing_inodes_);
  std::vector<std::string> roots;
  for (auto& p : missing_inodes_)
    AddRootsForBlockDevice(p.first, &roots);

  PERFETTO_DCHECK(file_scanner_.get() == nullptr);
  auto weak_this = GetWeakPtr();
  PERFETTO_DLOG("Starting scan of %s", DbgFmt(roots).c_str());
  file_scanner_ = std::unique_ptr<FileScanner>(new FileScanner(
      std::move(roots), this, scan_interval_ms_, scan_batch_size_));

  file_scanner_->Scan(task_runner_);
}

base::WeakPtr<InodeFileDataSource> InodeFileDataSource::GetWeakPtr() const {
  return weak_factory_.GetWeakPtr();
}

}  // namespace perfetto
