/*
 * 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() {}

 private:
  bool OnInodeFound(BlockDeviceID block_device_id,
                    Inode inode_number,
                    const std::string& path,
                    InodeFileMap_Entry_Type type) {
    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() {}
  std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>* map_;
};

}  // namespace

// static
constexpr int InodeFileDataSource::kTypeId;

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(
    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, kTypeId),
      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 std::vector<std::pair<Inode, BlockDeviceID>>& 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.get()->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 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(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
