Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/gmp/GMPStorageChild.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "GMPStorageChild.h"
7
#include "GMPChild.h"
8
#include "gmp-storage.h"
9
#include "base/task.h"
10
11
0
#define ON_GMP_THREAD() (mPlugin->GMPMessageLoop() == MessageLoop::current())
12
13
#define CALL_ON_GMP_THREAD(_func, ...) \
14
0
  do { \
15
0
    if (ON_GMP_THREAD()) { \
16
0
      _func(__VA_ARGS__); \
17
0
    } else { \
18
0
      mPlugin->GMPMessageLoop()->PostTask( \
19
0
        dont_add_new_uses_of_this::NewRunnableMethod(this, &GMPStorageChild::_func, ##__VA_ARGS__) \
20
0
      ); \
21
0
    } \
22
0
  } while(false)
23
24
static nsTArray<uint8_t>
25
ToArray(const uint8_t* aData, uint32_t aDataSize)
26
0
{
27
0
  nsTArray<uint8_t> data;
28
0
  data.AppendElements(aData, aDataSize);
29
0
  return data;
30
0
}
31
32
namespace mozilla {
33
namespace gmp {
34
35
GMPRecordImpl::GMPRecordImpl(GMPStorageChild* aOwner,
36
                             const nsCString& aName,
37
                             GMPRecordClient* aClient)
38
  : mName(aName)
39
  , mClient(aClient)
40
  , mOwner(aOwner)
41
0
{
42
0
}
43
44
GMPErr
45
GMPRecordImpl::Open()
46
0
{
47
0
  return mOwner->Open(this);
48
0
}
49
50
void
51
GMPRecordImpl::OpenComplete(GMPErr aStatus)
52
0
{
53
0
  mClient->OpenComplete(aStatus);
54
0
}
55
56
GMPErr
57
GMPRecordImpl::Read()
58
0
{
59
0
  return mOwner->Read(this);
60
0
}
61
62
void
63
GMPRecordImpl::ReadComplete(GMPErr aStatus,
64
                            const uint8_t* aBytes,
65
                            uint32_t aLength)
66
0
{
67
0
  mClient->ReadComplete(aStatus, aBytes, aLength);
68
0
}
69
70
GMPErr
71
GMPRecordImpl::Write(const uint8_t* aData, uint32_t aDataSize)
72
0
{
73
0
  return mOwner->Write(this, aData, aDataSize);
74
0
}
75
76
void
77
GMPRecordImpl::WriteComplete(GMPErr aStatus)
78
0
{
79
0
  mClient->WriteComplete(aStatus);
80
0
}
81
82
GMPErr
83
GMPRecordImpl::Close()
84
0
{
85
0
  RefPtr<GMPRecordImpl> kungfuDeathGrip(this);
86
0
  // Delete our self reference.
87
0
  Release();
88
0
  mOwner->Close(this->Name());
89
0
  return GMPNoErr;
90
0
}
91
92
GMPStorageChild::GMPStorageChild(GMPChild* aPlugin)
93
  : mMonitor("GMPStorageChild")
94
  , mPlugin(aPlugin)
95
  , mShutdown(false)
96
0
{
97
0
  MOZ_ASSERT(ON_GMP_THREAD());
98
0
}
99
100
GMPErr
101
GMPStorageChild::CreateRecord(const nsCString& aRecordName,
102
                              GMPRecord** aOutRecord,
103
                              GMPRecordClient* aClient)
104
0
{
105
0
  MonitorAutoLock lock(mMonitor);
106
0
107
0
  if (mShutdown) {
108
0
    NS_WARNING("GMPStorage used after it's been shutdown!");
109
0
    return GMPClosedErr;
110
0
  }
111
0
112
0
  MOZ_ASSERT(aRecordName.Length() && aOutRecord);
113
0
114
0
  if (HasRecord(aRecordName)) {
115
0
    return GMPRecordInUse;
116
0
  }
117
0
118
0
  RefPtr<GMPRecordImpl> record(new GMPRecordImpl(this, aRecordName, aClient));
119
0
  mRecords.Put(aRecordName, record); // Addrefs
120
0
121
0
  // The GMPRecord holds a self reference until the GMP calls Close() on
122
0
  // it. This means the object is always valid (even if neutered) while
123
0
  // the GMP expects it to be.
124
0
  record.forget(aOutRecord);
125
0
126
0
  return GMPNoErr;
127
0
}
128
129
bool
130
GMPStorageChild::HasRecord(const nsCString& aRecordName)
131
0
{
132
0
  mMonitor.AssertCurrentThreadOwns();
133
0
  return mRecords.Contains(aRecordName);
134
0
}
135
136
already_AddRefed<GMPRecordImpl>
137
GMPStorageChild::GetRecord(const nsCString& aRecordName)
138
0
{
139
0
  MonitorAutoLock lock(mMonitor);
140
0
  RefPtr<GMPRecordImpl> record;
141
0
  mRecords.Get(aRecordName, getter_AddRefs(record));
142
0
  return record.forget();
143
0
}
144
145
GMPErr
146
GMPStorageChild::Open(GMPRecordImpl* aRecord)
147
0
{
148
0
  MonitorAutoLock lock(mMonitor);
149
0
150
0
  if (mShutdown) {
151
0
    NS_WARNING("GMPStorage used after it's been shutdown!");
152
0
    return GMPClosedErr;
153
0
  }
154
0
155
0
  if (!HasRecord(aRecord->Name())) {
156
0
    // Trying to re-open a record that has already been closed.
157
0
    return GMPClosedErr;
158
0
  }
159
0
160
0
  CALL_ON_GMP_THREAD(SendOpen, aRecord->Name());
161
0
162
0
  return GMPNoErr;
163
0
}
164
165
GMPErr
166
GMPStorageChild::Read(GMPRecordImpl* aRecord)
167
0
{
168
0
  MonitorAutoLock lock(mMonitor);
169
0
170
0
  if (mShutdown) {
171
0
    NS_WARNING("GMPStorage used after it's been shutdown!");
172
0
    return GMPClosedErr;
173
0
  }
174
0
175
0
  if (!HasRecord(aRecord->Name())) {
176
0
    // Record not opened.
177
0
    return GMPClosedErr;
178
0
  }
179
0
180
0
  CALL_ON_GMP_THREAD(SendRead, aRecord->Name());
181
0
182
0
  return GMPNoErr;
183
0
}
184
185
GMPErr
186
GMPStorageChild::Write(GMPRecordImpl* aRecord,
187
                       const uint8_t* aData,
188
                       uint32_t aDataSize)
189
0
{
190
0
  if (aDataSize > GMP_MAX_RECORD_SIZE) {
191
0
    return GMPQuotaExceededErr;
192
0
  }
193
0
194
0
  MonitorAutoLock lock(mMonitor);
195
0
196
0
  if (mShutdown) {
197
0
    NS_WARNING("GMPStorage used after it's been shutdown!");
198
0
    return GMPClosedErr;
199
0
  }
200
0
201
0
  if (!HasRecord(aRecord->Name())) {
202
0
    // Record not opened.
203
0
    return GMPClosedErr;
204
0
  }
205
0
206
0
  CALL_ON_GMP_THREAD(SendWrite, aRecord->Name(), ToArray(aData, aDataSize));
207
0
208
0
  return GMPNoErr;
209
0
}
210
211
GMPErr
212
GMPStorageChild::Close(const nsCString& aRecordName)
213
0
{
214
0
  MonitorAutoLock lock(mMonitor);
215
0
216
0
  if (!HasRecord(aRecordName)) {
217
0
    // Already closed.
218
0
    return GMPClosedErr;
219
0
  }
220
0
221
0
  mRecords.Remove(aRecordName);
222
0
223
0
  if (!mShutdown) {
224
0
    CALL_ON_GMP_THREAD(SendClose, aRecordName);
225
0
  }
226
0
227
0
  return GMPNoErr;
228
0
}
229
230
mozilla::ipc::IPCResult
231
GMPStorageChild::RecvOpenComplete(const nsCString& aRecordName,
232
                                  const GMPErr& aStatus)
233
0
{
234
0
  // We don't need a lock to read |mShutdown| since it is only changed in
235
0
  // the GMP thread.
236
0
  if (mShutdown) {
237
0
    return IPC_OK();
238
0
  }
239
0
  RefPtr<GMPRecordImpl> record = GetRecord(aRecordName);
240
0
  if (!record) {
241
0
    // Not fatal.
242
0
    return IPC_OK();
243
0
  }
244
0
  record->OpenComplete(aStatus);
245
0
  return IPC_OK();
246
0
}
247
248
mozilla::ipc::IPCResult
249
GMPStorageChild::RecvReadComplete(const nsCString& aRecordName,
250
                                  const GMPErr& aStatus,
251
                                  InfallibleTArray<uint8_t>&& aBytes)
252
0
{
253
0
  if (mShutdown) {
254
0
    return IPC_OK();
255
0
  }
256
0
  RefPtr<GMPRecordImpl> record = GetRecord(aRecordName);
257
0
  if (!record) {
258
0
    // Not fatal.
259
0
    return IPC_OK();
260
0
  }
261
0
  record->ReadComplete(aStatus, aBytes.Elements(), aBytes.Length());
262
0
  return IPC_OK();
263
0
}
264
265
mozilla::ipc::IPCResult
266
GMPStorageChild::RecvWriteComplete(const nsCString& aRecordName,
267
                                   const GMPErr& aStatus)
268
0
{
269
0
  if (mShutdown) {
270
0
    return IPC_OK();
271
0
  }
272
0
  RefPtr<GMPRecordImpl> record = GetRecord(aRecordName);
273
0
  if (!record) {
274
0
    // Not fatal.
275
0
    return IPC_OK();
276
0
  }
277
0
  record->WriteComplete(aStatus);
278
0
  return IPC_OK();
279
0
}
280
281
mozilla::ipc::IPCResult
282
GMPStorageChild::RecvShutdown()
283
0
{
284
0
  // Block any new storage requests, and thus any messages back to the
285
0
  // parent. We don't delete any objects here, as that may invalidate
286
0
  // GMPRecord pointers held by the GMP.
287
0
  MonitorAutoLock lock(mMonitor);
288
0
  mShutdown = true;
289
0
  return IPC_OK();
290
0
}
291
292
} // namespace gmp
293
} // namespace mozilla
294
295
// avoid redefined macro in unified build
296
#undef ON_GMP_THREAD
297
#undef CALL_ON_GMP_THREAD