Refactor CdmFile interface to read/write files in the browser process

Instead of returning a base::File object and letting the utility process
do the read/write operations, change the mojo interface so that the operations
are instead done inside the browser process, and pass the contents to/from
the utility process.

This is done to simplify the code and is the first part of a change to make
CdmFile operations use streams instead of base::File.

Bug: 958204
Test: Modified tests pass
Change-Id: I3d01c4a848889ad0f5f3780305a00481b1ae0074
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1636438
Commit-Queue: John Rummell <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: Xiaohan Wang <[email protected]>
Cr-Commit-Position: refs/heads/master@{#669024}
diff --git a/content/browser/media/cdm_file_impl.h b/content/browser/media/cdm_file_impl.h
index 9d9b1a48..e34e77c 100644
--- a/content/browser/media/cdm_file_impl.h
+++ b/content/browser/media/cdm_file_impl.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_MEDIA_CDM_FILE_IMPL_H_
 
 #include <string>
+#include <vector>
 
 #include "base/callback_forward.h"
 #include "base/files/file.h"
@@ -28,6 +29,10 @@
 // mojo pipe as CdmStorageImpl, to enforce message dispatch order.
 class CdmFileImpl final : public media::mojom::CdmFile {
  public:
+  // Check whether |name| is valid as a usable file name. Returns true if it is,
+  // false otherwise.
+  static bool IsValidName(const std::string& name);
+
   CdmFileImpl(const std::string& file_name,
               const url::Origin& origin,
               const std::string& file_system_id,
@@ -35,54 +40,51 @@
               scoped_refptr<storage::FileSystemContext> file_system_context);
   ~CdmFileImpl() final;
 
-  // Called to open the file for read initially. Will create a file with
-  // |file_name_| if it does not exist. |file_opened_callback| will be called
-  // with the opened file descriptor on success. |file|.error_details()
-  // = base::File::FILE_ERROR_IN_USE if the file is in use by other CDMs
-  // or by the system. Note that |file_opened_callback| may destroy |this|
-  // (especially if the file can not be opened).
-  // Note that |this| should not be used anymore if Initialize() fails.
-  using OpenFileCallback = base::OnceCallback<void(base::File file)>;
-  void Initialize(OpenFileCallback file_opened_callback);
+  // Called to grab a lock on the file. Returns false if the file is in use by
+  // other CDMs or by the system, true otherwise. Note that |this| should not
+  // be used anymore if Initialize() fails.
+  bool Initialize();
 
-  // media::mojom::CdmFile implementation. |callback| will be called with the
-  // file descriptor on success. Otherwise the file descriptor will not be
-  // valid, and error_details() provides the reason.
-  void OpenFileForWriting(OpenFileForWritingCallback callback) final;
-  void CommitWrite(CommitWriteCallback callback) final;
+  // media::mojom::CdmFile implementation.
+  void Read(ReadCallback callback) final;
+  void Write(const std::vector<uint8_t>& data, WriteCallback callback) final;
 
  private:
   using CreateOrOpenCallback = storage::AsyncFileUtil::CreateOrOpenCallback;
 
-  // Keep track of which files are locked.
-  //   kFileLocked: Only the original file |file_name_| is locked.
-  //   kFileAndTempFileLocked: Both |file_name_| and |temp_file_name_| are
-  //                           locked.
-  // Initialize() can only be called if kNone, results in kFileLocked (on
-  // success). OpenFileForWriting() can only be called if kFileLocked, results
-  // in kFileAndTempFileLocked. CommitWrite() can only be called if
-  // kFileAndTempFileLocked, results in kFileLocked (temp file closed and then
-  // renamed to replace the original).
-  enum class LockState { kNone, kFileLocked, kFileAndTempFileLocked };
-
   // Open the file |file_name| using the flags provided in |file_flags|.
   // |callback| is called with the result.
   void OpenFile(const std::string& file_name,
                 uint32_t file_flags,
                 CreateOrOpenCallback callback);
 
-  void OnFileOpenedForReading(base::File file,
+  // Called when the file has been opened for reading, so it reads the contents
+  // of |file| and passes them to |callback|. |file| is closed after reading.
+  void OnFileOpenedForReading(ReadCallback callback,
+                              base::File file,
                               base::OnceClosure on_close_callback);
-  void OnTempFileOpenedForWriting(base::File file,
+  void OnFileRead(ReadCallback callback, Status status);
+
+  // Called when |temp_file_name_| has been opened for writing. Writes
+  // |data| to |file|, closes |file|, and then kicks off a rename of
+  // |temp_file_name_| to |file_name_|, effectively replacing the contents of
+  // the old file.
+  void OnTempFileOpenedForWriting(std::vector<uint8_t> data,
+                                  WriteCallback callback,
+                                  base::File file,
                                   base::OnceClosure on_close_callback);
-  void OnFileRenamed(base::File::Error move_result);
+  void OnFileWritten(WriteCallback callback, Status status);
+  void OnFileRenamed(WriteCallback callback, base::File::Error move_result);
+
+  // Deletes |file_name_| asynchronously.
+  void DeleteFile(WriteCallback callback);
+  void OnFileDeleted(WriteCallback callback, base::File::Error result);
 
   // Returns the FileSystemURL for the specified |file_name|.
   storage::FileSystemURL CreateFileSystemURL(const std::string& file_name);
 
   // Helper methods to lock and unlock a file.
   bool AcquireFileLock(const std::string& file_name);
-  bool IsFileLockHeld(const std::string& file_name);
   void ReleaseFileLock(const std::string& file_name);
 
   // Names of the files this class represents.
@@ -96,21 +98,16 @@
   const std::string file_system_root_uri_;
   scoped_refptr<storage::FileSystemContext> file_system_context_;
 
-  // Keep track of which files are opened.
-  LockState lock_state_ = LockState::kNone;
+  // Keep track of when the original file |file_name_| is locked.
+  // Initialize() can only be called if false and takes the lock (on success).
+  // Read() and Write() can only be called if true.
+  // Note that having a lock on |file_name| implies that |temp_file_name| is
+  // reserved for use by this object only, and an explicit lock on
+  // |temp_file_name| is not required.
+  bool file_locked_ = false;
 
-  // As only one open operation is allowed at a time, |pending_open_callback_|
-  // keeps track of the callback to be called when the file is opened. This
-  // ensures the callback is always called if we are destroyed while the open
-  // operation is running.
-  OpenFileCallback pending_open_callback_;
-
-  // Callbacks required to close the file when it's no longer needed.
-  // storage::AsyncFileUtil::CreateOrOpen() returns this callback on a
-  // successful open along with the base::File object, which should be
-  // called when the file is closed.
-  base::OnceClosure on_close_callback_;
-  base::OnceClosure temporary_file_on_close_callback_;
+  // Buffer used when reading the file.
+  std::vector<uint8_t> data_;
 
   THREAD_CHECKER(thread_checker_);
   base::WeakPtrFactory<CdmFileImpl> weak_factory_;