diff --git a/odrefresh/Android.bp b/odrefresh/Android.bp
index 530a714..d1729a1 100644
--- a/odrefresh/Android.bp
+++ b/odrefresh/Android.bp
@@ -30,7 +30,6 @@ cc_defaults {
         "odrefresh.cc",
         "odr_common.cc",
         "odr_compilation_log.cc",
-        "odr_fs_utils.cc",
         "odr_metrics.cc",
     ],
     local_include_dirs: ["include"],
diff --git a/odrefresh/odr_fs_utils.cc b/odrefresh/odr_fs_utils.cc
index 2a77e52..d4725a6 100644
--- a/odrefresh/odr_fs_utils.cc
+++ b/odrefresh/odr_fs_utils.cc
@@ -1,147 +1 @@
-/*
- * Copyright (C) 2021 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 "odr_fs_utils.h"
-
-#include <dirent.h>
-#include <ftw.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <unistd.h>
-
-#include <iosfwd>
-#include <memory>
-#include <ostream>
-#include <queue>
-#include <string>
-#include <string_view>
-#include <type_traits>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/strings.h>
-#include <base/os.h>
-
-namespace art {
-namespace odrefresh {
-
-// Callback for use with nftw(3) to assist with clearing files and sub-directories.
-// This method removes files and directories below the top-level directory passed to nftw().
-static int NftwCleanUpCallback(const char* fpath,
-                               [[maybe_unused]] const struct stat* sb,
-                               int typeflag,
-                               struct FTW* ftwbuf) {
-  switch (typeflag) {
-    case FTW_F:
-      return unlink(fpath);
-    case FTW_DP:
-      return (ftwbuf->level == 0) ? 0 : rmdir(fpath);
-    default:
-      return -1;
-  }
-}
-
-WARN_UNUSED bool RemoveDirectory(const std::string& dir_path) {
-  if (!OS::DirectoryExists(dir_path.c_str())) {
-    return true;
-  }
-
-  static constexpr int kMaxDescriptors = 4;  // Limit the need for nftw() to re-open descriptors.
-  if (nftw(dir_path.c_str(), NftwCleanUpCallback, kMaxDescriptors, FTW_DEPTH | FTW_MOUNT) != 0) {
-    LOG(ERROR) << "Failed to clean-up '" << dir_path << "'";
-    return false;
-  }
-
-  if (rmdir(dir_path.c_str()) != 0) {
-    // It's possible that we are not able to remove the directory itself. For example, when
-    // odrefresh is running in CompOS, the staging dir is prepared beforehand passed to the VM as an
-    // FD. In this case, just log and ignore the error. It's okay to keep the directory.
-    LOG(WARNING) << "Failed to delete '" << dir_path << "'";
-  }
-
-  return true;
-}
-
-WARN_UNUSED bool EnsureDirectoryExists(const std::string& absolute_path) {
-  if (absolute_path.empty() || absolute_path[0] != '/') {
-    LOG(ERROR) << "Path not absolute '" << absolute_path << "'";
-    return false;
-  }
-  std::string path;
-  for (const std::string& directory : android::base::Split(absolute_path, "/")) {
-    path.append("/").append(directory);
-    if (!OS::DirectoryExists(path.c_str())) {
-      static constexpr mode_t kDirectoryMode = S_IRWXU | S_IRGRP | S_IXGRP| S_IROTH | S_IXOTH;
-      if (mkdir(path.c_str(), kDirectoryMode) != 0) {
-        PLOG(ERROR) << "Could not create directory: " << path;
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-bool GetFreeSpace(const std::string& path, uint64_t* bytes) {
-  struct statvfs sv;
-  if (statvfs(path.c_str(), &sv) != 0) {
-    PLOG(ERROR) << "statvfs '" << path << "'";
-    return false;
-  }
-  *bytes = sv.f_bfree * sv.f_bsize;
-  return true;
-}
-
-bool GetUsedSpace(const std::string& path, uint64_t* bytes) {
-  static constexpr std::string_view kCurrentDirectory{"."};
-  static constexpr std::string_view kParentDirectory{".."};
-  static constexpr size_t kBytesPerBlock = 512;  // see manual page for stat(2).
-
-  uint64_t file_bytes = 0;
-  std::queue<std::string> unvisited;
-  unvisited.push(path);
-  while (!unvisited.empty()) {
-    std::string current = unvisited.front();
-    unvisited.pop();
-    std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(current.c_str()), closedir);
-    if (!dir) {
-      continue;
-    }
-    for (auto entity = readdir(dir.get()); entity != nullptr; entity = readdir(dir.get())) {
-      std::string_view name{entity->d_name};
-      if (name == kCurrentDirectory || name == kParentDirectory) {
-        continue;
-      }
-      std::string entity_name = current + "/" + entity->d_name;
-      if (entity->d_type == DT_DIR) {
-        unvisited.push(entity_name.c_str());
-      } else if (entity->d_type == DT_REG) {
-        struct stat sb;
-        if (stat(entity_name.c_str(), &sb) != 0) {
-          PLOG(ERROR) << "Failed to stat() file " << entity_name;
-          continue;
-        }
-        file_bytes += sb.st_blocks * kBytesPerBlock;
-      }
-    }
-  }
-  *bytes = file_bytes;
-  return true;
-}
-
-}  // namespace odrefresh
-}  // namespace art
+// Implementation moved to odr_fs_utils.h to resolve build issues.
diff --git a/odrefresh/odr_fs_utils.h b/odrefresh/odr_fs_utils.h
index 61f8651..4b84bee 100644
--- a/odrefresh/odr_fs_utils.h
+++ b/odrefresh/odr_fs_utils.h
@@ -17,29 +17,141 @@
 #ifndef ART_ODREFRESH_ODR_FS_UTILS_H_
 #define ART_ODREFRESH_ODR_FS_UTILS_H_
 
+#include <dirent.h>
+#include <ftw.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <unistd.h>
+
 #include <cstdint>
 #include <iosfwd>
+#include <memory>
+#include <ostream>
+#include <queue>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <vector>
 
+#include <android-base/logging.h>
 #include <android-base/macros.h>
+#include <android-base/strings.h>
+#include <base/os.h>
 
 namespace art {
 namespace odrefresh {
 
+// Callback for use with nftw(3) to assist with clearing files and sub-directories.
+// This method removes files and directories below the top-level directory passed to nftw().
+inline int NftwCleanUpCallback(const char* fpath,
+                               [[maybe_unused]] const struct stat* sb,
+                               int typeflag,
+                               struct FTW* ftwbuf) {
+  switch (typeflag) {
+    case FTW_F:
+      return unlink(fpath);
+    case FTW_DP:
+      return (ftwbuf->level == 0) ? 0 : rmdir(fpath);
+    default:
+      return -1;
+  }
+}
+
 // Removes the directory at `dir_path`, first removing all files and sub-directories in it.
 // Returns true on success, false otherwise.
-WARN_UNUSED bool RemoveDirectory(const std::string& dir_path);
+WARN_UNUSED inline bool RemoveDirectory(const std::string& dir_path) {
+  if (!OS::DirectoryExists(dir_path.c_str())) {
+    return true;
+  }
+
+  static constexpr int kMaxDescriptors = 4;  // Limit the need for nftw() to re-open descriptors.
+  if (nftw(dir_path.c_str(), NftwCleanUpCallback, kMaxDescriptors, FTW_DEPTH | FTW_MOUNT) != 0) {
+    LOG(ERROR) << "Failed to clean-up '" << dir_path << "'";
+    return false;
+  }
+
+  if (rmdir(dir_path.c_str()) != 0) {
+    // It's possible that we are not able to remove the directory itself. For example, when
+    // odrefresh is running in CompOS, the staging dir is prepared beforehand passed to the VM as an
+    // FD. In this case, just log and ignore the error. It's okay to keep the directory.
+    LOG(WARNING) << "Failed to delete '" << dir_path << "'";
+  }
+
+  return true;
+}
 
 // Create all directories on `absolute_dir_path`.
 // Returns true on success, false otherwise.
-WARN_UNUSED bool EnsureDirectoryExists(const std::string& absolute_dir_path);
+WARN_UNUSED inline bool EnsureDirectoryExists(const std::string& absolute_path) {
+  if (absolute_path.empty() || absolute_path[0] != '/') {
+    LOG(ERROR) << "Path not absolute '" << absolute_path << "'";
+    return false;
+  }
+  std::string path;
+  for (const std::string& directory : android::base::Split(absolute_path, "/")) {
+    path.append("/").append(directory);
+    if (!OS::DirectoryExists(path.c_str())) {
+      static constexpr mode_t kDirectoryMode = S_IRWXU | S_IRGRP | S_IXGRP| S_IROTH | S_IXOTH;
+      if (mkdir(path.c_str(), kDirectoryMode) != 0) {
+        PLOG(ERROR) << "Could not create directory: " << path;
+        return false;
+      }
+    }
+  }
+  return true;
+}
 
 // Get free space for filesystem containing `path`.
 // Returns true on success, false otherwise.
-WARN_UNUSED bool GetFreeSpace(const std::string& path, uint64_t* bytes);
+WARN_UNUSED inline bool GetFreeSpace(const std::string& path, uint64_t* bytes) {
+  struct statvfs sv;
+  if (statvfs(path.c_str(), &sv) != 0) {
+    PLOG(ERROR) << "statvfs '" << path << "'";
+    return false;
+  }
+  *bytes = sv.f_bfree * sv.f_bsize;
+  return true;
+}
 
 // Gets space used under directory `dir_path`.
 // Returns true on success, false otherwise.
-WARN_UNUSED bool GetUsedSpace(const std::string& dir_path, uint64_t* bytes);
+WARN_UNUSED inline bool GetUsedSpace(const std::string& path, uint64_t* bytes) {
+  static constexpr std::string_view kCurrentDirectory{"."};
+  static constexpr std::string_view kParentDirectory{".."};
+  static constexpr size_t kBytesPerBlock = 512;  // see manual page for stat(2).
+
+  uint64_t file_bytes = 0;
+  std::queue<std::string> unvisited;
+  unvisited.push(path);
+  while (!unvisited.empty()) {
+    std::string current = unvisited.front();
+    unvisited.pop();
+    std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(current.c_str()), closedir);
+    if (!dir) {
+      continue;
+    }
+    for (auto entity = readdir(dir.get()); entity != nullptr; entity = readdir(dir.get())) {
+      std::string_view name{entity->d_name};
+      if (name == kCurrentDirectory || name == kParentDirectory) {
+        continue;
+      }
+      std::string entity_name = current + "/" + entity->d_name;
+      if (entity->d_type == DT_DIR) {
+        unvisited.push(entity_name.c_str());
+      } else if (entity->d_type == DT_REG) {
+        struct stat sb;
+        if (stat(entity_name.c_str(), &sb) != 0) {
+          PLOG(ERROR) << "Failed to stat() file " << entity_name;
+          continue;
+        }
+        file_bytes += sb.st_blocks * kBytesPerBlock;
+      }
+    }
+  }
+  *bytes = file_bytes;
+  return true;
+}
 
 }  // namespace odrefresh
 }  // namespace art
