summaryrefslogtreecommitdiffstats
path: root/dom/system/gonk/MozMtpDatabase.h
blob: 8b308762e8b8124671284d1e95df7f60840038df (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_system_mozmtpdatabase_h__
#define mozilla_system_mozmtpdatabase_h__

#include "MozMtpCommon.h"

#include "mozilla/Mutex.h"
#include "mozilla/RefPtr.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsIThread.h"
#include "nsTArray.h"

class DeviceStorageFile;

BEGIN_MTP_NAMESPACE // mozilla::system::mtp

class RefCountedMtpServer;

using namespace android;

class MozMtpDatabase final : public MtpDatabase
{
public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpDatabase)

  MozMtpDatabase();

  // called from SendObjectInfo to reserve a database entry for the incoming file
  virtual MtpObjectHandle beginSendObject(const char* aPath,
                                          MtpObjectFormat aFormat,
                                          MtpObjectHandle aParent,
                                          MtpStorageID aStorageID,
                                          uint64_t aSize,
                                          time_t aModified);

  // called to report success or failure of the SendObject file transfer
  // success should signal a notification of the new object's creation,
  // failure should remove the database entry created in beginSendObject
  virtual void endSendObject(const char* aPath,
                             MtpObjectHandle aHandle,
                             MtpObjectFormat aFormat,
                             bool aSucceeded);

  virtual MtpObjectHandleList* getObjectList(MtpStorageID aStorageID,
                                             MtpObjectFormat aFormat,
                                             MtpObjectHandle aParent);

  virtual int getNumObjects(MtpStorageID aStorageID,
                            MtpObjectFormat aFormat,
                            MtpObjectHandle aParent);

  virtual MtpObjectFormatList* getSupportedPlaybackFormats();

  virtual MtpObjectFormatList* getSupportedCaptureFormats();

  virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat aFormat);

  virtual MtpDevicePropertyList* getSupportedDeviceProperties();

  virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle aHandle,
                                                 MtpObjectProperty aProperty,
                                                 MtpDataPacket& aPacket);

  virtual MtpResponseCode setObjectPropertyValue(MtpObjectHandle aHandle,
                                                 MtpObjectProperty aProperty,
                                                 MtpDataPacket& aPacket);

  virtual MtpResponseCode getDevicePropertyValue(MtpDeviceProperty aProperty,
                                                 MtpDataPacket& aPacket);

  virtual MtpResponseCode setDevicePropertyValue(MtpDeviceProperty aProperty,
                                                 MtpDataPacket& aPacket);

  virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty aProperty);

  virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle aHandle,
                                                uint32_t aFormat,
                                                uint32_t aProperty,
                                                int aGroupCode,
                                                int aDepth,
                                                MtpDataPacket& aPacket);

  virtual MtpResponseCode getObjectInfo(MtpObjectHandle aHandle,
                                        MtpObjectInfo& aInfo);

  virtual void* getThumbnail(MtpObjectHandle aHandle, size_t& aOutThumbSize);

  virtual MtpResponseCode getObjectFilePath(MtpObjectHandle aHandle,
                                            MtpString& aOutFilePath,
                                            int64_t& aOutFileLength,
                                            MtpObjectFormat& aOutFormat);

  virtual MtpResponseCode deleteFile(MtpObjectHandle aHandle);

  virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle aHandle);

  virtual MtpResponseCode setObjectReferences(MtpObjectHandle aHandle,
                                              MtpObjectHandleList* aReferences);

  virtual MtpProperty* getObjectPropertyDesc(MtpObjectProperty aProperty,
                                             MtpObjectFormat aFormat);

  virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty aProperty);

  virtual void sessionStarted();

  virtual void sessionEnded();

  void AddStorage(MtpStorageID aStorageID, const char* aPath, const char *aName);
  void RemoveStorage(MtpStorageID aStorageID);

  void MtpWatcherUpdate(RefCountedMtpServer* aMtpServer,
                        DeviceStorageFile* aFile,
                        const nsACString& aEventType);

protected:
  virtual ~MozMtpDatabase();

private:

  struct DbEntry final
  {
    DbEntry()
      : mHandle(0),
        mStorageID(0),
        mObjectFormat(MTP_FORMAT_DEFINED),
        mParent(0),
        mObjectSize(0),
        mDateCreated(0),
        mDateModified(0),
        mDateAdded(0) {}

    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DbEntry)

    MtpObjectHandle mHandle;        // uint32_t
    MtpStorageID    mStorageID;     // uint32_t
    nsCString       mObjectName;
    MtpObjectFormat mObjectFormat;  // uint16_t
    MtpObjectHandle mParent;        // uint32_t
    uint64_t        mObjectSize;
    nsCString       mDisplayName;
    nsCString       mPath;
    time_t          mDateCreated;
    time_t          mDateModified;
    time_t          mDateAdded;

  protected:
    ~DbEntry() {}
  };

  template<class T>
  class ProtectedTArray : private nsTArray<T>
  {
  public:
    typedef T elem_type;
    typedef typename nsTArray<T>::size_type size_type;
    typedef typename nsTArray<T>::index_type index_type;
    typedef nsTArray<T> base_type;

    static const index_type NoIndex = base_type::NoIndex;

    ProtectedTArray(mozilla::Mutex& aMutex)
      : mMutex(aMutex)
    {}

    size_type Length() const
    {
      // GRR - This assert prints to stderr and won't show up in logcat.
      mMutex.AssertCurrentThreadOwns();
      return base_type::Length();
    }

    template <class Item>
    elem_type* AppendElement(const Item& aItem)
    {
      mMutex.AssertCurrentThreadOwns();
      return base_type::AppendElement(aItem);
    }

    void Clear()
    {
      mMutex.AssertCurrentThreadOwns();
      base_type::Clear();
    }

    void RemoveElementAt(index_type aIndex)
    {
      mMutex.AssertCurrentThreadOwns();
      base_type::RemoveElementAt(aIndex);
    }

    elem_type& operator[](index_type aIndex)
    {
      mMutex.AssertCurrentThreadOwns();
      return base_type::ElementAt(aIndex);
    }

    const elem_type& operator[](index_type aIndex) const
    {
      mMutex.AssertCurrentThreadOwns();
      return base_type::ElementAt(aIndex);
    }

  private:
    mozilla::Mutex& mMutex;
  };
  typedef nsTArray<RefPtr<DbEntry> > UnprotectedDbArray;
  typedef ProtectedTArray<RefPtr<DbEntry> > ProtectedDbArray;

  struct StorageEntry final
  {
    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageEntry)

    MtpStorageID  mStorageID;
    nsCString     mStoragePath;
    nsCString     mStorageName;

  protected:
    ~StorageEntry() {}
  };
  typedef ProtectedTArray<RefPtr<StorageEntry> > StorageArray;

  enum MatchType
  {
    MatchAll,
    MatchHandle,
    MatchParent,
    MatchFormat,
    MatchHandleFormat,
    MatchParentFormat,
  };

  bool IsValidHandle(MtpObjectHandle aHandle)
  {
    return aHandle > 0 && aHandle < mDb.Length();
  }

  void AddEntry(DbEntry* aEntry);
  void AddEntryAndNotify(DbEntry* aEntr, RefCountedMtpServer* aMtpServer);
  void DumpEntries(const char* aLabel);
  MtpObjectHandle FindEntryByPath(const nsACString& aPath);
  already_AddRefed<DbEntry> GetEntry(MtpObjectHandle aHandle);
  void RemoveEntry(MtpObjectHandle aHandle);
  void RemoveEntryAndNotify(MtpObjectHandle aHandle, RefCountedMtpServer* aMtpServer);
  void UpdateEntry(MtpObjectHandle aHandle, DeviceStorageFile* aFile);
  void UpdateEntryAndNotify(MtpObjectHandle aHandle, DeviceStorageFile* aFile,
                            RefCountedMtpServer* aMtpServer);
  void QueryEntries(MatchType aMatchType, uint32_t aMatchField1,
                    uint32_t aMatchField2, UnprotectedDbArray& aResult);

  nsCString BaseName(const nsCString& aPath);


  MtpObjectHandle GetNextHandle()
  {
    return mDb.Length();
  }

  void AddDirectory(MtpStorageID aStorageID, const char *aPath, MtpObjectHandle aParent);

  void CreateEntryForFileAndNotify(const nsACString& aPath,
                                   DeviceStorageFile* aFile,
                                   RefCountedMtpServer* aMtpServer);

  StorageArray::index_type FindStorage(MtpStorageID aStorageID);
  MtpStorageID FindStorageIDFor(const nsACString& aPath, nsCSubstring& aRemainder);
  void MtpWatcherNotify(DbEntry* aEntry, const char* aEventType);

  // We need a mutex to protext mDb and mStorage. The MTP server runs on a
  // dedicated thread, and it updates/accesses mDb. When files are updated
  // through DeviceStorage, we need to update/access mDb and mStorage as well
  // (from a non-MTP server thread).
  mozilla::Mutex mMutex;
  ProtectedDbArray mDb;
  StorageArray mStorage;

  bool mBeginSendObjectCalled;
};

END_MTP_NAMESPACE

#endif // mozilla_system_mozmtpdatabase_h__