Bug 1357323 - Remove the gonk code that was referenced by the build system. r=gps

--HG--
extra : rebase_source : 1d30ebcbdbcf596c944e1eec981f85db341485e5
This commit is contained in:
Mike Hommey 2017-04-18 17:46:39 +09:00
Родитель 34e619d1c1
Коммит 33a7e408ce
269 изменённых файлов: 0 добавлений и 97634 удалений

Просмотреть файл

@ -1,84 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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/. */
#include "ISOControl.h"
#include "ISOMediaBoxes.h"
#include "AMRBox.h"
#include "ISOTrackMetadata.h"
namespace mozilla {
nsresult
AMRSampleEntry::Generate(uint32_t* aBoxSize)
{
uint32_t box_size;
nsresult rv = amr_special_box->Generate(&box_size);
NS_ENSURE_SUCCESS(rv, rv);
size += box_size;
*aBoxSize = size;
return NS_OK;
}
nsresult
AMRSampleEntry::Write()
{
BoxSizeChecker checker(mControl, size);
nsresult rv;
rv = AudioSampleEntry::Write();
NS_ENSURE_SUCCESS(rv, rv);
rv = amr_special_box->Write();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
AMRSampleEntry::AMRSampleEntry(ISOControl* aControl)
: AudioSampleEntry(NS_LITERAL_CSTRING("samr"), aControl)
{
amr_special_box = new AMRSpecificBox(aControl);
MOZ_COUNT_CTOR(AMRSampleEntry);
}
AMRSampleEntry::~AMRSampleEntry()
{
MOZ_COUNT_DTOR(AMRSampleEntry);
}
nsresult
AMRSpecificBox::Generate(uint32_t* aBoxSize)
{
nsresult rv;
FragmentBuffer* frag = mControl->GetFragment(Audio_Track);
rv = frag->GetCSD(amrDecSpecInfo);
NS_ENSURE_SUCCESS(rv, rv);
size += amrDecSpecInfo.Length();
*aBoxSize = size;
return NS_OK;
}
nsresult
AMRSpecificBox::Write()
{
BoxSizeChecker checker(mControl, size);
Box::Write();
mControl->Write(amrDecSpecInfo.Elements(), amrDecSpecInfo.Length());
return NS_OK;
}
AMRSpecificBox::AMRSpecificBox(ISOControl* aControl)
: Box(NS_LITERAL_CSTRING("damr"), aControl)
{
MOZ_COUNT_CTOR(AMRSpecificBox);
}
AMRSpecificBox::~AMRSpecificBox()
{
MOZ_COUNT_DTOR(AMRSpecificBox);
}
}

Просмотреть файл

@ -1,50 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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 AMRBOX_h_
#define AMRBOX_h_
#include "nsTArray.h"
#include "MuxerOperation.h"
namespace mozilla {
class ISOControl;
// 3GPP TS 26.244 6.7 'AMRSpecificBox field for AMRSampleEntry box'
// Box type: 'damr'
class AMRSpecificBox : public Box {
public:
// 3GPP members
nsTArray<uint8_t> amrDecSpecInfo;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// AMRSpecificBox methods
AMRSpecificBox(ISOControl* aControl);
~AMRSpecificBox();
};
// 3GPP TS 26.244 6.5 'AMRSampleEntry box'
// Box type: 'sawb'
class AMRSampleEntry : public AudioSampleEntry {
public:
// 3GPP members
RefPtr<AMRSpecificBox> amr_special_box;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// AMRSampleEntry methods
AMRSampleEntry(ISOControl* aControl);
~AMRSampleEntry();
};
}
#endif // AMRBOX_h_

Просмотреть файл

@ -1,87 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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/. */
#include <climits>
#include "ISOControl.h"
#include "ISOMediaBoxes.h"
#include "AVCBox.h"
namespace mozilla {
nsresult
AVCSampleEntry::Generate(uint32_t* aBoxSize)
{
uint32_t avc_box_size = 0;
nsresult rv;
rv = avcConfigBox->Generate(&avc_box_size);
NS_ENSURE_SUCCESS(rv, rv);
size += avc_box_size;
*aBoxSize = size;
return NS_OK;
}
nsresult
AVCSampleEntry::Write()
{
BoxSizeChecker checker(mControl, size);
nsresult rv;
rv = VisualSampleEntry::Write();
NS_ENSURE_SUCCESS(rv, rv);
rv = avcConfigBox->Write();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
AVCSampleEntry::AVCSampleEntry(ISOControl* aControl)
: VisualSampleEntry(NS_LITERAL_CSTRING("avc1"), aControl)
{
avcConfigBox = new AVCConfigurationBox(aControl);
MOZ_COUNT_CTOR(AVCSampleEntry);
}
AVCSampleEntry::~AVCSampleEntry()
{
MOZ_COUNT_DTOR(AVCSampleEntry);
}
AVCConfigurationBox::AVCConfigurationBox(ISOControl* aControl)
: Box(NS_LITERAL_CSTRING("avcC"), aControl)
{
MOZ_COUNT_CTOR(AVCConfigurationBox);
}
AVCConfigurationBox::~AVCConfigurationBox()
{
MOZ_COUNT_DTOR(AVCConfigurationBox);
}
nsresult
AVCConfigurationBox::Generate(uint32_t* aBoxSize)
{
nsresult rv;
FragmentBuffer* frag = mControl->GetFragment(Video_Track);
rv = frag->GetCSD(avcConfig);
NS_ENSURE_SUCCESS(rv, rv);
size += avcConfig.Length();
*aBoxSize = size;
return NS_OK;
}
nsresult
AVCConfigurationBox::Write()
{
BoxSizeChecker checker(mControl, size);
Box::Write();
mControl->Write(avcConfig.Elements(), avcConfig.Length());
return NS_OK;
}
}

Просмотреть файл

@ -1,59 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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 AVCBox_h_
#define AVCBox_h_
#include "nsTArray.h"
#include "ISOMediaBoxes.h"
namespace mozilla {
class ISOControl;
// 14496-12 8.5.2.2
#define resolution_72_dpi 0x00480000
#define video_depth 0x0018
// 14496-15 5.3.4.1 'Sample description name and format'
// Box type: 'avcC'
class AVCConfigurationBox : public Box {
public:
// ISO BMFF members
// avcConfig is CodecSpecificData from 14496-15 '5.3.4.1 Sample description
// name and format.
// These data are generated by encoder and we encapsulated the generated
// bitstream into box directly.
nsTArray<uint8_t> avcConfig;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// AVCConfigurationBox methods
AVCConfigurationBox(ISOControl* aControl);
~AVCConfigurationBox();
};
// 14496-15 5.3.4.1 'Sample description name and format'
// Box type: 'avc1'
class AVCSampleEntry : public VisualSampleEntry {
public:
// ISO BMFF members
RefPtr<AVCConfigurationBox> avcConfigBox;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// VisualSampleEntry methods
AVCSampleEntry(ISOControl* aControl);
~AVCSampleEntry();
};
}
#endif // AVCBox_h_

Просмотреть файл

@ -1,84 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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/. */
#include "ISOControl.h"
#include "ISOMediaBoxes.h"
#include "EVRCBox.h"
#include "ISOTrackMetadata.h"
namespace mozilla {
nsresult
EVRCSampleEntry::Generate(uint32_t* aBoxSize)
{
uint32_t box_size;
nsresult rv = evrc_special_box->Generate(&box_size);
NS_ENSURE_SUCCESS(rv, rv);
size += box_size;
*aBoxSize = size;
return NS_OK;
}
nsresult
EVRCSampleEntry::Write()
{
BoxSizeChecker checker(mControl, size);
nsresult rv;
rv = AudioSampleEntry::Write();
NS_ENSURE_SUCCESS(rv, rv);
rv = evrc_special_box->Write();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
EVRCSampleEntry::EVRCSampleEntry(ISOControl* aControl)
: AudioSampleEntry(NS_LITERAL_CSTRING("sevc"), aControl)
{
evrc_special_box = new EVRCSpecificBox(aControl);
MOZ_COUNT_CTOR(EVRCSampleEntry);
}
EVRCSampleEntry::~EVRCSampleEntry()
{
MOZ_COUNT_DTOR(EVRCSampleEntry);
}
nsresult
EVRCSpecificBox::Generate(uint32_t* aBoxSize)
{
nsresult rv;
FragmentBuffer* frag = mControl->GetFragment(Audio_Track);
rv = frag->GetCSD(evrcDecSpecInfo);
NS_ENSURE_SUCCESS(rv, rv);
size += evrcDecSpecInfo.Length();
*aBoxSize = size;
return NS_OK;
}
nsresult
EVRCSpecificBox::Write()
{
BoxSizeChecker checker(mControl, size);
Box::Write();
mControl->Write(evrcDecSpecInfo.Elements(), evrcDecSpecInfo.Length());
return NS_OK;
}
EVRCSpecificBox::EVRCSpecificBox(ISOControl* aControl)
: Box(NS_LITERAL_CSTRING("devc"), aControl)
{
MOZ_COUNT_CTOR(EVRCSpecificBox);
}
EVRCSpecificBox::~EVRCSpecificBox()
{
MOZ_COUNT_DTOR(EVRCSpecificBox);
}
}

Просмотреть файл

@ -1,50 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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 EVRCBOX_h_
#define EVRCBOX_h_
#include "nsTArray.h"
#include "MuxerOperation.h"
namespace mozilla {
class ISOControl;
// 3GPP TS 26.244 6.7 'EVRCSpecificBox field for EVRCSampleEntry box'
// Box type: 'devc'
class EVRCSpecificBox : public Box {
public:
// 3GPP members
nsTArray<uint8_t> evrcDecSpecInfo;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// EVRCSpecificBox methods
EVRCSpecificBox(ISOControl* aControl);
~EVRCSpecificBox();
};
// 3GPP TS 26.244 6.5 'EVRCSampleEntry box'
// Box type: 'sevc'
class EVRCSampleEntry : public AudioSampleEntry {
public:
// 3GPP members
RefPtr<EVRCSpecificBox> evrc_special_box;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// EVRCSampleEntry methods
EVRCSampleEntry(ISOControl* aControl);
~EVRCSampleEntry();
};
}
#endif // EVRCBOX_h_

Просмотреть файл

@ -1,415 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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/. */
#include <time.h>
#include "nsAutoPtr.h"
#include "ISOControl.h"
#include "ISOMediaBoxes.h"
#include "EncodedFrameContainer.h"
namespace mozilla {
// For MP4 creation_time and modification_time offset from January 1, 1904 to
// January 1, 1970.
#define iso_time_offset 2082844800
FragmentBuffer::FragmentBuffer(uint32_t aTrackType, uint32_t aFragDuration)
: mTrackType(aTrackType)
, mFragDuration(aFragDuration)
, mMediaStartTime(0)
, mFragmentNumber(0)
, mLastFrameTimeOfLastFragment(0)
, mEOS(false)
{
mFragArray.AppendElement();
MOZ_COUNT_CTOR(FragmentBuffer);
}
FragmentBuffer::~FragmentBuffer()
{
MOZ_COUNT_DTOR(FragmentBuffer);
}
bool
FragmentBuffer::HasEnoughData()
{
// Audio or video frame is enough to form a moof.
return (mFragArray.Length() > 1);
}
nsresult
FragmentBuffer::GetCSD(nsTArray<uint8_t>& aCSD)
{
if (!mCSDFrame) {
return NS_ERROR_FAILURE;
}
aCSD.AppendElements(mCSDFrame->GetFrameData().Elements(),
mCSDFrame->GetFrameData().Length());
return NS_OK;
}
nsresult
FragmentBuffer::AddFrame(EncodedFrame* aFrame)
{
// already EOS, it rejects all new data.
if (mEOS) {
MOZ_ASSERT(0);
return NS_OK;
}
EncodedFrame::FrameType type = aFrame->GetFrameType();
if (type == EncodedFrame::AAC_CSD || type == EncodedFrame::AVC_CSD ||
type == EncodedFrame::AMR_AUDIO_CSD || type == EncodedFrame::EVRC_AUDIO_CSD) {
mCSDFrame = aFrame;
// Use CSD's timestamp as the start time. Encoder should send CSD frame first
// and then data frames.
mMediaStartTime = aFrame->GetTimeStamp();
mFragmentNumber = 1;
return NS_OK;
}
// if the timestamp is incorrect, abort it.
if (aFrame->GetTimeStamp() < mMediaStartTime) {
MOZ_ASSERT(false);
return NS_ERROR_FAILURE;
}
mFragArray.LastElement().AppendElement(aFrame);
// check if current fragment is reach the fragment duration.
if ((aFrame->GetTimeStamp() - mMediaStartTime) >= (mFragDuration * mFragmentNumber)) {
mFragArray.AppendElement();
mFragmentNumber++;
}
return NS_OK;
}
nsresult
FragmentBuffer::GetFirstFragment(nsTArray<RefPtr<EncodedFrame>>& aFragment,
bool aFlush)
{
// It should be called only if there is a complete fragment in mFragArray.
if (mFragArray.Length() <= 1 && !mEOS) {
MOZ_ASSERT(false);
return NS_ERROR_FAILURE;
}
if (aFlush) {
aFragment.SwapElements(mFragArray.ElementAt(0));
mFragArray.RemoveElementAt(0);
} else {
aFragment.AppendElements(mFragArray.ElementAt(0));
}
return NS_OK;
}
uint32_t
FragmentBuffer::GetFirstFragmentSampleNumber()
{
return mFragArray.ElementAt(0).Length();
}
uint32_t
FragmentBuffer::GetFirstFragmentSampleSize()
{
uint32_t size = 0;
uint32_t len = mFragArray.ElementAt(0).Length();
for (uint32_t i = 0; i < len; i++) {
size += mFragArray.ElementAt(0).ElementAt(i)->GetFrameData().Length();
}
return size;
}
ISOControl::ISOControl(uint32_t aMuxingType)
: mMuxingType(aMuxingType)
, mAudioFragmentBuffer(nullptr)
, mVideoFragmentBuffer(nullptr)
, mFragNum(0)
, mOutputSize(0)
, mBitCount(0)
, mBit(0)
{
// Create a data array for first mp4 Box, ftyp.
mOutBuffers.SetLength(1);
MOZ_COUNT_CTOR(ISOControl);
}
ISOControl::~ISOControl()
{
MOZ_COUNT_DTOR(ISOControl);
}
uint32_t
ISOControl::GetNextTrackID()
{
return (mMetaArray.Length() + 1);
}
uint32_t
ISOControl::GetTrackID(TrackMetadataBase::MetadataKind aKind)
{
for (uint32_t i = 0; i < mMetaArray.Length(); i++) {
if (mMetaArray[i]->GetKind() == aKind) {
return (i + 1);
}
}
// Track ID shouldn't be 0. It must be something wrong here.
MOZ_ASSERT(0);
return 0;
}
nsresult
ISOControl::SetMetadata(TrackMetadataBase* aTrackMeta)
{
if (aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AAC ||
aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AMR ||
aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AVC ||
aTrackMeta->GetKind() == TrackMetadataBase::METADATA_EVRC) {
mMetaArray.AppendElement(aTrackMeta);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
nsresult
ISOControl::GetAudioMetadata(RefPtr<AudioTrackMetadata>& aAudMeta)
{
for (uint32_t i = 0; i < mMetaArray.Length() ; i++) {
if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AAC ||
mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AMR ||
mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_EVRC) {
aAudMeta = static_cast<AudioTrackMetadata*>(mMetaArray[i].get());
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
nsresult
ISOControl::GetVideoMetadata(RefPtr<VideoTrackMetadata>& aVidMeta)
{
for (uint32_t i = 0; i < mMetaArray.Length() ; i++) {
if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AVC) {
aVidMeta = static_cast<VideoTrackMetadata*>(mMetaArray[i].get());
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
bool
ISOControl::HasAudioTrack()
{
RefPtr<AudioTrackMetadata> audMeta;
GetAudioMetadata(audMeta);
return audMeta;
}
bool
ISOControl::HasVideoTrack()
{
RefPtr<VideoTrackMetadata> vidMeta;
GetVideoMetadata(vidMeta);
return vidMeta;
}
nsresult
ISOControl::SetFragment(FragmentBuffer* aFragment)
{
if (aFragment->GetType() == Audio_Track) {
mAudioFragmentBuffer = aFragment;
} else {
mVideoFragmentBuffer = aFragment;
}
return NS_OK;
}
FragmentBuffer*
ISOControl::GetFragment(uint32_t aType)
{
if (aType == Audio_Track) {
return mAudioFragmentBuffer;
} else if (aType == Video_Track){
return mVideoFragmentBuffer;
}
MOZ_ASSERT(0);
return nullptr;
}
nsresult
ISOControl::GetBufs(nsTArray<nsTArray<uint8_t>>* aOutputBufs)
{
uint32_t len = mOutBuffers.Length();
for (uint32_t i = 0; i < len; i++) {
mOutBuffers[i].SwapElements(*aOutputBufs->AppendElement());
}
return FlushBuf();
}
nsresult
ISOControl::FlushBuf()
{
mOutBuffers.SetLength(1);
return NS_OK;
}
uint32_t
ISOControl::WriteAVData(nsTArray<uint8_t>& aArray)
{
MOZ_ASSERT(!mBitCount);
uint32_t len = aArray.Length();
if (!len) {
return 0;
}
mOutputSize += len;
// The last element already has data, allocated a new element for pointer
// swapping.
if (mOutBuffers.LastElement().Length()) {
mOutBuffers.AppendElement();
}
// Swap the video/audio data pointer.
mOutBuffers.LastElement().SwapElements(aArray);
// Following data could be boxes, so appending a new uint8_t array here.
mOutBuffers.AppendElement();
return len;
}
uint32_t
ISOControl::WriteBits(uint64_t aBits, size_t aNumBits)
{
uint8_t output_byte = 0;
MOZ_ASSERT(aNumBits <= 64);
// TODO: rewritten following with bitset?
for (size_t i = aNumBits; i > 0; i--) {
mBit |= (((aBits >> (i - 1)) & 1) << (8 - ++mBitCount));
if (mBitCount == 8) {
Write(&mBit, sizeof(uint8_t));
mBit = 0;
mBitCount = 0;
output_byte++;
}
}
return output_byte;
}
uint32_t
ISOControl::Write(uint8_t* aBuf, uint32_t aSize)
{
mOutBuffers.LastElement().AppendElements(aBuf, aSize);
mOutputSize += aSize;
return aSize;
}
uint32_t
ISOControl::Write(uint8_t aData)
{
MOZ_ASSERT(!mBitCount);
Write((uint8_t*)&aData, sizeof(uint8_t));
return sizeof(uint8_t);
}
uint32_t
ISOControl::GetBufPos()
{
uint32_t len = mOutBuffers.Length();
uint32_t pos = 0;
for (uint32_t i = 0; i < len; i++) {
pos += mOutBuffers.ElementAt(i).Length();
}
return pos;
}
uint32_t
ISOControl::WriteFourCC(const char* aType)
{
// Bit operation should be aligned to byte before writing any byte data.
MOZ_ASSERT(!mBitCount);
uint32_t size = strlen(aType);
if (size == 4) {
return Write((uint8_t*)aType, size);
}
return 0;
}
nsresult
ISOControl::GenerateFtyp()
{
nsresult rv;
uint32_t size;
nsAutoPtr<FileTypeBox> type_box(new FileTypeBox(this));
rv = type_box->Generate(&size);
NS_ENSURE_SUCCESS(rv, rv);
rv = type_box->Write();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
ISOControl::GenerateMoov()
{
nsresult rv;
uint32_t size;
nsAutoPtr<MovieBox> moov_box(new MovieBox(this));
rv = moov_box->Generate(&size);
NS_ENSURE_SUCCESS(rv, rv);
rv = moov_box->Write();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
ISOControl::GenerateMoof(uint32_t aTrackType)
{
mFragNum++;
nsresult rv;
uint32_t size;
uint64_t first_sample_offset = mOutputSize;
nsAutoPtr<MovieFragmentBox> moof_box(new MovieFragmentBox(aTrackType, this));
nsAutoPtr<MediaDataBox> mdat_box(new MediaDataBox(aTrackType, this));
rv = moof_box->Generate(&size);
NS_ENSURE_SUCCESS(rv, rv);
first_sample_offset += size;
rv = mdat_box->Generate(&size);
NS_ENSURE_SUCCESS(rv, rv);
first_sample_offset += mdat_box->FirstSampleOffsetInMediaDataBox();
// correct offset info
nsTArray<RefPtr<MuxerOperation>> tfhds;
rv = moof_box->Find(NS_LITERAL_CSTRING("tfhd"), tfhds);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t len = tfhds.Length();
for (uint32_t i = 0; i < len; i++) {
TrackFragmentHeaderBox* tfhd = (TrackFragmentHeaderBox*) tfhds.ElementAt(i).get();
rv = tfhd->UpdateBaseDataOffset(first_sample_offset);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = moof_box->Write();
NS_ENSURE_SUCCESS(rv, rv);
rv = mdat_box->Write();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
uint32_t
ISOControl::GetTime()
{
return (uint64_t)time(nullptr) + iso_time_offset;
}
}

Просмотреть файл

@ -1,250 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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 ISOCOMPOSITOR_H_
#define ISOCOMPOSITOR_H_
#include "mozilla/EndianUtils.h"
#include "nsTArray.h"
#include "ISOTrackMetadata.h"
#include "EncodedFrameContainer.h"
namespace mozilla {
class Box;
class ISOControl;
/**
* This class collects elementary stream data to form a fragment.
* ISOMediaWriter will check if the data is enough; if yes, the corresponding
* moof will be created and write to ISOControl.
* Each audio and video has its own fragment and only one during the whole
* life cycle, when a fragment is formed in ISOControl, Flush() needs to
* be called to reset it.
*/
class FragmentBuffer {
public:
// aTrackType: it could be Audio_Track or Video_Track.
// aFragDuration: it is the fragment duration. (microsecond per unit)
// Audio and video have the same fragment duration.
FragmentBuffer(uint32_t aTrackType, uint32_t aFragDuration);
~FragmentBuffer();
// Get samples of first fragment, that will swap all the elements in the
// mFragArray[0] when aFlush = true, and caller is responsible for drop
// EncodedFrame reference count.
nsresult GetFirstFragment(nsTArray<RefPtr<EncodedFrame>>& aFragment,
bool aFlush = false);
// Add sample frame to the last element fragment of mFragArray. If sample
// number is enough, it will append a new fragment element. And the new
// sample will be added to the new fragment element of mFragArray.
nsresult AddFrame(EncodedFrame* aFrame);
// Get total sample size of first complete fragment size.
uint32_t GetFirstFragmentSampleSize();
// Get sample number of first complete fragment.
uint32_t GetFirstFragmentSampleNumber();
// Check if it accumulates enough frame data.
// It returns true when data is enough to form a fragment.
bool HasEnoughData();
// Called by ISOMediaWriter when TrackEncoder has sent the last frame. The
// remains frame data will form the last moof and move the state machine to
// in ISOMediaWriter to last phrase.
nsresult SetEndOfStream() {
mEOS = true;
return NS_OK;
}
bool EOS() { return mEOS; }
// CSD (codec specific data), it is generated by encoder and the data depends
// on codec type. This data will be sent as a special frame from encoder to
// ISOMediaWriter and pass to this class via AddFrame().
nsresult GetCSD(nsTArray<uint8_t>& aCSD);
bool HasCSD() { return mCSDFrame; }
uint32_t GetType() { return mTrackType; }
void SetLastFragmentLastFrameTime(uint32_t aTime) {
mLastFrameTimeOfLastFragment = aTime;
}
uint32_t GetLastFragmentLastFrameTime() {
return mLastFrameTimeOfLastFragment;
}
private:
uint32_t mTrackType;
// Fragment duration, microsecond per unit.
uint32_t mFragDuration;
// Media start time, microsecond per unit.
// Together with mFragDuration, mFragmentNumber and EncodedFrame->GetTimeStamp(),
// when the difference between current frame time and mMediaStartTime is
// exceeded current fragment ceiling timeframe, that means current fragment has
// enough data and a new element in mFragArray will be added.
uint64_t mMediaStartTime;
// Current fragment number. It will be increase when a new element of
// mFragArray is created.
// Note:
// It only means the fragment number of current accumulated frames, not
// the current 'creating' fragment mFragNum in ISOControl.
uint32_t mFragmentNumber;
// The last frame time stamp of last fragment. It is for calculating the
// play duration of first frame in current fragment. The frame duration is
// defined as "current frame timestamp - last frame timestamp" here. So it
// needs to keep the last timestamp of last fragment.
uint32_t mLastFrameTimeOfLastFragment;
// Array of fragments, each element has enough samples to form a
// complete fragment.
nsTArray<nsTArray<RefPtr<EncodedFrame>>> mFragArray;
// Codec specific data frame, it will be generated by encoder and send to
// ISOMediaWriter through WriteEncodedTrack(). The data will be vary depends
// on codec type.
RefPtr<EncodedFrame> mCSDFrame;
// END_OF_STREAM from ContainerWriter
bool mEOS;
};
/**
* ISOControl will be carried to each box when box is created. It is the main
* bridge for box to output stream to ContainerWriter and retrieve information.
* ISOControl acts 3 different roles:
* 1. Holds the pointer of audio metadata, video metadata, fragment and
* pass them to boxes.
* 2. Provide the functions to generate the base structure of MP4; they are
* GenerateFtyp, GenerateMoov, GenerateMoof, and GenerateMfra.
* 3. The actually writer used by MuxOperation::Write() in each box. It provides
* writing methods for different kind of data; they are Write, WriteArray,
* WriteBits...etc.
*/
class ISOControl {
friend class Box;
public:
ISOControl(uint32_t aMuxingType);
~ISOControl();
nsresult GenerateFtyp();
nsresult GenerateMoov();
nsresult GenerateMoof(uint32_t aTrackType);
// Swap elementary stream pointer to output buffers.
uint32_t WriteAVData(nsTArray<uint8_t>& aArray);
uint32_t Write(uint8_t* aBuf, uint32_t aSize);
uint32_t Write(uint8_t aData);
template <typename T>
uint32_t Write(T aData) {
MOZ_ASSERT(!mBitCount);
aData = NativeEndian::swapToNetworkOrder(aData);
Write((uint8_t*)&aData, sizeof(T));
return sizeof(T);
}
template <typename T>
uint32_t WriteArray(const T &aArray, uint32_t aSize) {
MOZ_ASSERT(!mBitCount);
uint32_t size = 0;
for (uint32_t i = 0; i < aSize; i++) {
size += Write(aArray[i]);
}
return size;
}
uint32_t WriteFourCC(const char* aType);
// Bit writing. Note: it needs to be byte-boundary before using
// others non-bit writing function.
uint32_t WriteBits(uint64_t aBits, size_t aNumBits);
// This is called by GetContainerData and swap all the buffers to aOutputBuffers.
nsresult GetBufs(nsTArray<nsTArray<uint8_t>>* aOutputBufs);
// Presentation time in seconds since midnight, Jan. 1, 1904, in UTC time.
uint32_t GetTime();
// current fragment number
uint32_t GetCurFragmentNumber() { return mFragNum; }
nsresult SetFragment(FragmentBuffer* aFragment);
FragmentBuffer* GetFragment(uint32_t aType);
uint32_t GetMuxingType() { return mMuxingType; }
nsresult SetMetadata(TrackMetadataBase* aTrackMeta);
nsresult GetAudioMetadata(RefPtr<AudioTrackMetadata>& aAudMeta);
nsresult GetVideoMetadata(RefPtr<VideoTrackMetadata>& aVidMeta);
// Track ID is the Metadata index in mMetaArray. It allows only 1 audio
// track and 1 video track in this muxer. In this muxer, it is prohibt to have
// mutiple audio track or video track in the same file.
uint32_t GetTrackID(TrackMetadataBase::MetadataKind aKind);
uint32_t GetNextTrackID();
bool HasAudioTrack();
bool HasVideoTrack();
private:
uint32_t GetBufPos();
nsresult FlushBuf();
// One of value in TYPE_XXX, defined in ISOMediaWriter.
uint32_t mMuxingType;
// Audio and video fragments are owned by ISOMediaWriter.
// They don't need to worry about pointer going stale because ISOMediaWriter's
// lifetime is longer than ISOControl.
FragmentBuffer* mAudioFragmentBuffer;
FragmentBuffer* mVideoFragmentBuffer;
// Generated fragment number
uint32_t mFragNum;
// The (index + 1) will be the track ID.
nsTArray<RefPtr<TrackMetadataBase>> mMetaArray;
// Array of output buffers.
// To save memory usage, audio/video sample will be swapped into a new element
// of this array.
//
// For example,
// mOutBuffers[0] --> boxes (allocated by muxer)
// mOutBuffers[1] --> video raw data (allocated by encoder)
// mOutBuffers[2] --> video raw data (allocated by encoder)
// mOutBuffers[3] --> video raw data (allocated by encoder)
// mOutBuffers[4] --> boxes (allocated by muxer)
// mOutBuffers[5] --> audio raw data (allocated by encoder)
// ...etc.
//
nsTArray<nsTArray<uint8_t>> mOutBuffers;
// Accumulate output size from Write().
uint64_t mOutputSize;
// Bit writing operation. Note: the mBitCount should be 0 before any
// byte-boundary writing method be called (Write(uint32_t), Write(uint16_t)...etc);
// otherwise, there will be assertion on these functions.
uint8_t mBitCount;
uint8_t mBit;
};
}
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,781 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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 ISOMediaBoxes_h_
#define ISOMediaBoxes_h_
#include <bitset>
#include "nsString.h"
#include "nsTArray.h"
#include "nsAutoPtr.h"
#include "MuxerOperation.h"
#include "mozilla/UniquePtr.h"
#define WRITE_FULLBOX(_compositor, _size) \
BoxSizeChecker checker(_compositor, _size); \
FullBox::Write();
#define FOURCC(a, b, c, d) ( ((a) << 24) | ((b) << 16) | ((c) << 8) | (d) )
namespace mozilla {
/**
* track type from spec 8.4.3.3
*/
#define Audio_Track 0x01
#define Video_Track 0x02
class AudioTrackMetadata;
class VideoTrackMetadata;
class ISOControl;
/**
* This is the base class for all ISO media format boxes.
* It provides the fields of box type(four CC) and size.
* The data members in the beginning of a Box (or its descendants)
* are the 14496-12 defined member. Other members prefix with 'm'
* are private control data.
*
* This class is for inherited only, it shouldn't be instanced directly.
*/
class Box : public MuxerOperation {
protected:
// ISO BMFF members
uint32_t size; // 14496-12 4-2 'Object Structure'. Size of this box.
nsCString boxType; // four CC name, all table names are listed in
// 14496-12 table 1.
public:
// MuxerOperation methods
nsresult Write() override;
nsresult Find(const nsACString& aType,
nsTArray<RefPtr<MuxerOperation>>& aOperations) override;
// This helper class will compare the written size in Write() and the size in
// Generate(). If their are not equal, it will assert.
class BoxSizeChecker {
public:
BoxSizeChecker(ISOControl* aControl, uint32_t aSize);
~BoxSizeChecker();
uint32_t ori_size;
uint32_t box_size;
ISOControl* mControl;
};
protected:
Box() = delete;
Box(const nsACString& aType, ISOControl* aControl);
ISOControl* mControl;
RefPtr<AudioTrackMetadata> mAudioMeta;
RefPtr<VideoTrackMetadata> mVideoMeta;
};
/**
* FullBox (and its descendants) is the box which contains the 'real' data
* members. It is the edge in the ISO box structure and it doesn't contain
* any box.
*
* This class is for inherited only, it shouldn't be instanced directly.
*/
class FullBox : public Box {
public:
// ISO BMFF members
uint8_t version; // 14496-12 4.2 'Object Structure'
std::bitset<24> flags; //
// MuxerOperation methods
nsresult Write() override;
protected:
// FullBox methods
FullBox(const nsACString& aType, uint8_t aVersion, uint32_t aFlags,
ISOControl* aControl);
FullBox() = delete;
};
/**
* The default implementation of the container box.
* Basically, the container box inherits this class and overrides the
* constructor only.
*
* According to 14496-12 3.1.1 'container box', a container box is
* 'box whose sole purpose is to contain and group a set of related boxes'
*
* This class is for inherited only, it shouldn't be instanced directly.
*/
class DefaultContainerImpl : public Box {
public:
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
nsresult Find(const nsACString& aType,
nsTArray<RefPtr<MuxerOperation>>& aOperations) override;
protected:
// DefaultContainerImpl methods
DefaultContainerImpl(const nsACString& aType, ISOControl* aControl);
DefaultContainerImpl() = delete;
nsTArray<RefPtr<MuxerOperation>> boxes;
};
// 14496-12 4.3 'File Type Box'
// Box type: 'ftyp'
class FileTypeBox : public Box {
public:
// ISO BMFF members
nsCString major_brand; // four chars
uint32_t minor_version;
nsTArray<nsCString> compatible_brands;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// FileTypeBox methods
FileTypeBox(ISOControl* aControl);
~FileTypeBox();
};
// 14496-12 8.2.1 'Movie Box'
// Box type: 'moov'
// MovieBox contains MovieHeaderBox, TrackBox and MovieExtendsBox.
class MovieBox : public DefaultContainerImpl {
public:
MovieBox(ISOControl* aControl);
~MovieBox();
};
// 14496-12 8.2.2 'Movie Header Box'
// Box type: 'mvhd'
class MovieHeaderBox : public FullBox {
public:
// ISO BMFF members
uint32_t creation_time;
uint32_t modification_time;
uint32_t timescale;
uint32_t duration;
uint32_t rate;
uint16_t volume;
uint16_t reserved16;
uint32_t reserved32[2];
uint32_t matrix[9];
uint32_t pre_defined[6];
uint32_t next_track_ID;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// MovieHeaderBox methods
MovieHeaderBox(ISOControl* aControl);
~MovieHeaderBox();
uint32_t GetTimeScale();
};
// 14496-12 8.4.2 'Media Header Box'
// Box type: 'mdhd'
class MediaHeaderBox : public FullBox {
public:
// ISO BMFF members
uint32_t creation_time;
uint32_t modification_time;
uint32_t timescale;
uint32_t duration;
std::bitset<1> pad;
std::bitset<5> lang1;
std::bitset<5> lang2;
std::bitset<5> lang3;
uint16_t pre_defined;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// MediaHeaderBox methods
MediaHeaderBox(uint32_t aType, ISOControl* aControl);
~MediaHeaderBox();
uint32_t GetTimeScale();
protected:
uint32_t mTrackType;
};
// 14496-12 8.3.1 'Track Box'
// Box type: 'trak'
// TrackBox contains TrackHeaderBox and MediaBox.
class TrackBox : public DefaultContainerImpl {
public:
TrackBox(uint32_t aTrackType, ISOControl* aControl);
~TrackBox();
};
// 14496-12 8.1.1 'Media Data Box'
// Box type: 'mdat'
class MediaDataBox : public Box {
public:
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// MediaDataBox methods
uint32_t GetAllSampleSize() { return mAllSampleSize; }
uint32_t FirstSampleOffsetInMediaDataBox() { return mFirstSampleOffset; }
MediaDataBox(uint32_t aTrackType, ISOControl* aControl);
~MediaDataBox();
protected:
uint32_t mAllSampleSize; // All audio and video sample size in this box.
uint32_t mFirstSampleOffset; // The offset of first sample in this box from
// the beginning of this mp4 file.
uint32_t mTrackType;
};
// flags for TrackRunBox::flags, 14496-12 8.8.8.1.
#define flags_data_offset_present 0x000001
#define flags_first_sample_flags_present 0x000002
#define flags_sample_duration_present 0x000100
#define flags_sample_size_present 0x000200
#define flags_sample_flags_present 0x000400
#define flags_sample_composition_time_offsets_present 0x000800
// flag for TrackRunBox::tbl::sample_flags and TrackExtendsBox::default_sample_flags
// which is defined in 14496-12 8.8.3.1.
uint32_t set_sample_flags(bool aSync);
// 14496-12 8.8.8 'Track Fragment Run Box'
// Box type: 'trun'
class TrackRunBox : public FullBox {
public:
// ISO BMFF members
typedef struct {
uint32_t sample_duration;
uint32_t sample_size;
uint32_t sample_flags;
uint32_t sample_composition_time_offset;
} tbl;
uint32_t sample_count;
// the following are optional fields
uint32_t data_offset; // data offset exists when audio/video are present in file.
uint32_t first_sample_flags;
UniquePtr<tbl[]> sample_info_table;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// TrackRunBox methods
uint32_t GetAllSampleSize() { return mAllSampleSize; }
nsresult SetDataOffset(uint32_t aOffset);
TrackRunBox(uint32_t aType, uint32_t aFlags, ISOControl* aControl);
~TrackRunBox();
protected:
uint32_t fillSampleTable();
uint32_t mAllSampleSize;
uint32_t mTrackType;
};
// tf_flags in TrackFragmentHeaderBox, 14496-12 8.8.7.1.
#define base_data_offset_present 0x000001
#define sample_description_index_present 0x000002
#define default_sample_duration_present 0x000008
#define default_sample_size_present 0x000010
#define default_sample_flags_present 0x000020
#define duration_is_empty 0x010000
#define default_base_is_moof 0x020000
// 14496-12 8.8.7 'Track Fragment Header Box'
// Box type: 'tfhd'
class TrackFragmentHeaderBox : public FullBox {
public:
// ISO BMFF members
uint32_t track_ID;
uint64_t base_data_offset;
uint32_t default_sample_duration;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// TrackFragmentHeaderBox methods
nsresult UpdateBaseDataOffset(uint64_t aOffset); // The offset of the first
// sample in file.
TrackFragmentHeaderBox(uint32_t aType, uint32_t aFlags, ISOControl* aControl);
~TrackFragmentHeaderBox();
protected:
uint32_t mTrackType;
};
// 14496-12 8.8.6 'Track Fragment Box'
// Box type: 'traf'
// TrackFragmentBox cotains TrackFragmentHeaderBox and TrackRunBox.
class TrackFragmentBox : public DefaultContainerImpl {
public:
TrackFragmentBox(uint32_t aType, ISOControl* aControl);
~TrackFragmentBox();
protected:
uint32_t mTrackType;
};
// 14496-12 8.8.5 'Movie Fragment Header Box'
// Box type: 'mfhd'
class MovieFragmentHeaderBox : public FullBox {
public:
// ISO BMFF members
uint32_t sequence_number;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// MovieFragmentHeaderBox methods
MovieFragmentHeaderBox(uint32_t aType, ISOControl* aControl);
~MovieFragmentHeaderBox();
protected:
uint32_t mTrackType;
};
// 14496-12 8.8.4 'Movie Fragment Box'
// Box type: 'moof'
// MovieFragmentBox contains MovieFragmentHeaderBox and TrackFragmentBox.
class MovieFragmentBox : public DefaultContainerImpl {
public:
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
// MovieFragmentBox methods
MovieFragmentBox(uint32_t aType, ISOControl* aControl);
~MovieFragmentBox();
protected:
uint32_t mTrackType;
};
// 14496-12 8.8.3 'Track Extends Box'
// Box type: 'trex'
class TrackExtendsBox : public FullBox {
public:
// ISO BMFF members
uint32_t track_ID;
uint32_t default_sample_description_index;
uint32_t default_sample_duration;
uint32_t default_sample_size;
uint32_t default_sample_flags;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// TrackExtendsBox methods
TrackExtendsBox(uint32_t aType, ISOControl* aControl);
~TrackExtendsBox();
protected:
uint32_t mTrackType;
};
// 14496-12 8.8.1 'Movie Extends Box'
// Box type: 'mvex'
// MovieExtendsBox contains TrackExtendsBox.
class MovieExtendsBox : public DefaultContainerImpl {
public:
MovieExtendsBox(ISOControl* aControl);
~MovieExtendsBox();
};
// 14496-12 8.7.5 'Chunk Offset Box'
// Box type: 'stco'
class ChunkOffsetBox : public FullBox {
public:
// ISO BMFF members
typedef struct {
uint32_t chunk_offset;
} tbl;
uint32_t entry_count;
UniquePtr<tbl[]> sample_tbl;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// ChunkOffsetBox methods
ChunkOffsetBox(uint32_t aType, ISOControl* aControl);
~ChunkOffsetBox();
protected:
uint32_t mTrackType;
};
// 14496-12 8.7.4 'Sample To Chunk Box'
// Box type: 'stsc'
class SampleToChunkBox : public FullBox {
public:
// ISO BMFF members
typedef struct {
uint32_t first_chunk;
uint32_t sample_per_chunk;
uint32_t sample_description_index;
} tbl;
uint32_t entry_count;
UniquePtr<tbl[]> sample_tbl;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// SampleToChunkBox methods
SampleToChunkBox(uint32_t aType, ISOControl* aControl);
~SampleToChunkBox();
protected:
uint32_t mTrackType;
};
// 14496-12 8.6.1.2 'Decoding Time to Sample Box'
// Box type: 'stts'
class TimeToSampleBox : public FullBox {
public:
// ISO BMFF members
typedef struct {
uint32_t sample_count;
uint32_t sample_delta;
} tbl;
uint32_t entry_count;
UniquePtr<tbl[]> sample_tbl;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// TimeToSampleBox methods
TimeToSampleBox(uint32_t aType, ISOControl* aControl);
~TimeToSampleBox();
protected:
uint32_t mTrackType;
};
/**
* 14496-12 8.5.2 'Sample Description Box'
* This is the base class for VisualSampleEntry and AudioSampleEntry.
*
* This class is for inherited only, it shouldn't be instanced directly.
*
* The inhertied tree of a codec box should be:
*
* +--> AVCSampleEntry
* +--> VisualSampleEntryBox +
* | +--> ...
* SampleEntryBox +
* | +--> MP4AudioSampleEntry
* +--> AudioSampleEntryBox +
* +--> AMRSampleEntry
* +
* +--> ...
*
*/
class SampleEntryBox : public Box {
public:
// ISO BMFF members
uint8_t reserved[6];
uint16_t data_reference_index;
// sampleentrybox methods
SampleEntryBox(const nsACString& aFormat, ISOControl* aControl);
// MuxerOperation methods
nsresult Write() override;
protected:
SampleEntryBox() = delete;
};
// 14496-12 8.5.2 'Sample Description Box'
// Box type: 'stsd'
class SampleDescriptionBox : public FullBox {
public:
// ISO BMFF members
uint32_t entry_count;
RefPtr<SampleEntryBox> sample_entry_box;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// SampleDescriptionBox methods
SampleDescriptionBox(uint32_t aType, ISOControl* aControl);
~SampleDescriptionBox();
protected:
nsresult CreateAudioSampleEntry(RefPtr<SampleEntryBox>& aSampleEntry);
nsresult CreateVideoSampleEntry(RefPtr<SampleEntryBox>& aSampleEntry);
uint32_t mTrackType;
};
// 14496-12 8.5.2.2
// The base class for audio codec box.
// This class is for inherited only, it shouldn't be instanced directly.
class AudioSampleEntry : public SampleEntryBox {
public:
// ISO BMFF members
uint16_t sound_version;
uint8_t reserved2[6];
uint16_t channels;
uint16_t sample_size;
uint16_t compressionId;
uint16_t packet_size;
uint32_t timeScale; // (sample rate of media) <<16
// MuxerOperation methods
nsresult Write() override;
~AudioSampleEntry();
protected:
AudioSampleEntry(const nsACString& aFormat, ISOControl* aControl);
};
// 14496-12 8.5.2.2
// The base class for video codec box.
// This class is for inherited only, it shouldn't be instanced directly.
class VisualSampleEntry : public SampleEntryBox {
public:
// ISO BMFF members
uint8_t reserved[16];
uint16_t width;
uint16_t height;
uint32_t horizresolution; // 72 dpi
uint32_t vertresolution; // 72 dpi
uint32_t reserved2;
uint16_t frame_count; // 1, defined in 14496-12 8.5.2.2
uint8_t compressorName[32];
uint16_t depth; // 0x0018, defined in 14496-12 8.5.2.2;
uint16_t pre_defined; // -1, defined in 14496-12 8.5.2.2;
// MuxerOperation methods
nsresult Write() override;
// VisualSampleEntry methods
~VisualSampleEntry();
protected:
VisualSampleEntry(const nsACString& aFormat, ISOControl* aControl);
};
// 14496-12 8.7.3.2 'Sample Size Box'
// Box type: 'stsz'
class SampleSizeBox : public FullBox {
public:
// ISO BMFF members
uint32_t sample_size;
uint32_t sample_count;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// SampleSizeBox methods
SampleSizeBox(ISOControl* aControl);
~SampleSizeBox();
};
// 14496-12 8.5.1 'Sample Table Box'
// Box type: 'stbl'
//
// SampleTableBox contains SampleDescriptionBox,
// TimeToSampleBox,
// SampleToChunkBox,
// SampleSizeBox and
// ChunkOffsetBox.
class SampleTableBox : public DefaultContainerImpl {
public:
SampleTableBox(uint32_t aType, ISOControl* aControl);
~SampleTableBox();
};
// 14496-12 8.7.2 'Data Reference Box'
// Box type: 'url '
class DataEntryUrlBox : public FullBox {
public:
// ISO BMFF members
// flags in DataEntryUrlBox::flags
const static uint16_t flags_media_at_the_same_file = 0x0001;
nsCString location;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// DataEntryUrlBox methods
DataEntryUrlBox();
DataEntryUrlBox(ISOControl* aControl);
DataEntryUrlBox(const DataEntryUrlBox& aBox);
~DataEntryUrlBox();
};
// 14496-12 8.7.2 'Data Reference Box'
// Box type: 'dref'
class DataReferenceBox : public FullBox {
public:
// ISO BMFF members
uint32_t entry_count;
nsTArray<nsAutoPtr<DataEntryUrlBox>> urls;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// DataReferenceBox methods
DataReferenceBox(ISOControl* aControl);
~DataReferenceBox();
};
// 14496-12 8.7.1 'Data Information Box'
// Box type: 'dinf'
// DataInformationBox contains DataReferenceBox.
class DataInformationBox : public DefaultContainerImpl {
public:
DataInformationBox(ISOControl* aControl);
~DataInformationBox();
};
// 14496-12 8.4.5.2 'Video Media Header Box'
// Box type: 'vmhd'
class VideoMediaHeaderBox : public FullBox {
public:
// ISO BMFF members
uint16_t graphicsmode;
uint16_t opcolor[3];
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// VideoMediaHeaderBox methods
VideoMediaHeaderBox(ISOControl* aControl);
~VideoMediaHeaderBox();
};
// 14496-12 8.4.5.3 'Sound Media Header Box'
// Box type: 'smhd'
class SoundMediaHeaderBox : public FullBox {
public:
// ISO BMFF members
uint16_t balance;
uint16_t reserved;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// SoundMediaHeaderBox methods
SoundMediaHeaderBox(ISOControl* aControl);
~SoundMediaHeaderBox();
};
// 14496-12 8.4.4 'Media Information Box'
// Box type: 'minf'
// MediaInformationBox contains SoundMediaHeaderBox, DataInformationBox and
// SampleTableBox.
class MediaInformationBox : public DefaultContainerImpl {
public:
MediaInformationBox(uint32_t aType, ISOControl* aControl);
~MediaInformationBox();
protected:
uint32_t mTrackType;
};
// flags for TrackHeaderBox::flags.
#define flags_track_enabled 0x000001
#define flags_track_in_movie 0x000002
#define flags_track_in_preview 0x000004
// 14496-12 8.3.2 'Track Header Box'
// Box type: 'tkhd'
class TrackHeaderBox : public FullBox {
public:
// ISO BMFF members
// version = 0
uint32_t creation_time;
uint32_t modification_time;
uint32_t track_ID;
uint32_t reserved;
uint32_t duration;
uint32_t reserved2[2];
uint16_t layer;
uint16_t alternate_group;
uint16_t volume;
uint16_t reserved3;
uint32_t matrix[9];
uint32_t width;
uint32_t height;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// TrackHeaderBox methods
TrackHeaderBox(uint32_t aType, ISOControl* aControl);
~TrackHeaderBox();
protected:
uint32_t mTrackType;
};
// 14496-12 8.4.3 'Handler Reference Box'
// Box type: 'hdlr'
class HandlerBox : public FullBox {
public:
// ISO BMFF members
uint32_t pre_defined;
uint32_t handler_type;
uint32_t reserved[3];
nsCString name;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// HandlerBox methods
HandlerBox(uint32_t aType, ISOControl* aControl);
~HandlerBox();
protected:
uint32_t mTrackType;
};
// 14496-12 8.4.1 'Media Box'
// Box type: 'mdia'
// MediaBox contains MediaHeaderBox, HandlerBox, and MediaInformationBox.
class MediaBox : public DefaultContainerImpl {
public:
MediaBox(uint32_t aType, ISOControl* aControl);
~MediaBox();
protected:
uint32_t mTrackType;
};
}
#endif // ISOMediaBoxes_h_

Просмотреть файл

@ -1,234 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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/. */
#include "ISOMediaWriter.h"
#include "ISOControl.h"
#include "ISOMediaBoxes.h"
#include "ISOTrackMetadata.h"
#include "nsThreadUtils.h"
#include "MediaEncoder.h"
#include "VideoUtils.h"
#include "GeckoProfiler.h"
#undef LOG
#ifdef MOZ_WIDGET_GONK
#include <android/log.h>
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "MediaEncoder", ## args);
#else
#define LOG(args, ...)
#endif
namespace mozilla {
const static uint32_t FRAG_DURATION = 2 * USECS_PER_S; // microsecond per unit
ISOMediaWriter::ISOMediaWriter(uint32_t aType, uint32_t aHint)
: ContainerWriter()
, mState(MUXING_HEAD)
, mBlobReady(false)
, mType(0)
{
if (aType & CREATE_AUDIO_TRACK) {
mType |= Audio_Track;
}
if (aType & CREATE_VIDEO_TRACK) {
mType |= Video_Track;
}
mControl = new ISOControl(aHint);
MOZ_COUNT_CTOR(ISOMediaWriter);
}
ISOMediaWriter::~ISOMediaWriter()
{
MOZ_COUNT_DTOR(ISOMediaWriter);
}
nsresult
ISOMediaWriter::RunState()
{
nsresult rv;
switch (mState) {
case MUXING_HEAD:
{
rv = mControl->GenerateFtyp();
NS_ENSURE_SUCCESS(rv, rv);
rv = mControl->GenerateMoov();
NS_ENSURE_SUCCESS(rv, rv);
mState = MUXING_FRAG;
break;
}
case MUXING_FRAG:
{
rv = mControl->GenerateMoof(mType);
NS_ENSURE_SUCCESS(rv, rv);
bool EOS;
if (ReadyToRunState(EOS) && EOS) {
mState = MUXING_DONE;
}
break;
}
case MUXING_DONE:
{
break;
}
}
mBlobReady = true;
return NS_OK;
}
nsresult
ISOMediaWriter::WriteEncodedTrack(const EncodedFrameContainer& aData,
uint32_t aFlags)
{
PROFILER_LABEL("ISOMediaWriter", "WriteEncodedTrack",
js::ProfileEntry::Category::OTHER);
// Muxing complete, it doesn't allowed to reentry again.
if (mState == MUXING_DONE) {
MOZ_ASSERT(false);
return NS_ERROR_FAILURE;
}
FragmentBuffer* frag = nullptr;
uint32_t len = aData.GetEncodedFrames().Length();
if (!len) {
// no frame? why bother to WriteEncodedTrack
return NS_OK;
}
for (uint32_t i = 0; i < len; i++) {
RefPtr<EncodedFrame> frame(aData.GetEncodedFrames()[i]);
EncodedFrame::FrameType type = frame->GetFrameType();
if (type == EncodedFrame::AAC_AUDIO_FRAME ||
type == EncodedFrame::AAC_CSD ||
type == EncodedFrame::AMR_AUDIO_FRAME ||
type == EncodedFrame::AMR_AUDIO_CSD ||
type == EncodedFrame::EVRC_AUDIO_FRAME ||
type == EncodedFrame::EVRC_AUDIO_CSD) {
frag = mAudioFragmentBuffer;
} else if (type == EncodedFrame::AVC_I_FRAME ||
type == EncodedFrame::AVC_P_FRAME ||
type == EncodedFrame::AVC_B_FRAME ||
type == EncodedFrame::AVC_CSD) {
frag = mVideoFragmentBuffer;
} else {
MOZ_ASSERT(0);
return NS_ERROR_FAILURE;
}
frag->AddFrame(frame);
}
// Encoder should send CSD (codec specific data) frame before sending the
// audio/video frames. When CSD data is ready, it is sufficient to generate a
// moov data. If encoder doesn't send CSD yet, muxer needs to wait before
// generating anything.
if (mType & Audio_Track && (!mAudioFragmentBuffer ||
!mAudioFragmentBuffer->HasCSD())) {
return NS_OK;
}
if (mType & Video_Track && (!mVideoFragmentBuffer ||
!mVideoFragmentBuffer->HasCSD())) {
return NS_OK;
}
// Only one FrameType in EncodedFrameContainer so it doesn't need to be
// inside the for-loop.
if (frag && (aFlags & END_OF_STREAM)) {
frag->SetEndOfStream();
}
nsresult rv;
bool EOS;
if (ReadyToRunState(EOS)) {
// Because track encoder won't generate new data after EOS, it needs to make
// sure the state reaches MUXING_DONE when EOS is signaled.
do {
rv = RunState();
} while (EOS && mState != MUXING_DONE);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
bool
ISOMediaWriter::ReadyToRunState(bool& aEOS)
{
aEOS = false;
bool bReadyToMux = true;
if ((mType & Audio_Track) && (mType & Video_Track)) {
if (!mAudioFragmentBuffer->HasEnoughData()) {
bReadyToMux = false;
}
if (!mVideoFragmentBuffer->HasEnoughData()) {
bReadyToMux = false;
}
if (mAudioFragmentBuffer->EOS() && mVideoFragmentBuffer->EOS()) {
aEOS = true;
bReadyToMux = true;
}
} else if (mType == Audio_Track) {
if (!mAudioFragmentBuffer->HasEnoughData()) {
bReadyToMux = false;
}
if (mAudioFragmentBuffer->EOS()) {
aEOS = true;
bReadyToMux = true;
}
} else if (mType == Video_Track) {
if (!mVideoFragmentBuffer->HasEnoughData()) {
bReadyToMux = false;
}
if (mVideoFragmentBuffer->EOS()) {
aEOS = true;
bReadyToMux = true;
}
}
return bReadyToMux;
}
nsresult
ISOMediaWriter::GetContainerData(nsTArray<nsTArray<uint8_t>>* aOutputBufs,
uint32_t aFlags)
{
PROFILER_LABEL("ISOMediaWriter", "GetContainerData",
js::ProfileEntry::Category::OTHER);
if (mBlobReady) {
if (mState == MUXING_DONE) {
mIsWritingComplete = true;
}
mBlobReady = false;
return mControl->GetBufs(aOutputBufs);
}
return NS_OK;
}
nsresult
ISOMediaWriter::SetMetadata(TrackMetadataBase* aMetadata)
{
PROFILER_LABEL("ISOMediaWriter", "SetMetadata",
js::ProfileEntry::Category::OTHER);
if (aMetadata->GetKind() == TrackMetadataBase::METADATA_AAC ||
aMetadata->GetKind() == TrackMetadataBase::METADATA_AMR ||
aMetadata->GetKind() == TrackMetadataBase::METADATA_EVRC) {
mControl->SetMetadata(aMetadata);
mAudioFragmentBuffer = new FragmentBuffer(Audio_Track, FRAG_DURATION);
mControl->SetFragment(mAudioFragmentBuffer);
return NS_OK;
}
if (aMetadata->GetKind() == TrackMetadataBase::METADATA_AVC) {
mControl->SetMetadata(aMetadata);
mVideoFragmentBuffer = new FragmentBuffer(Video_Track, FRAG_DURATION);
mControl->SetFragment(mVideoFragmentBuffer);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
} // namespace mozilla

Просмотреть файл

@ -1,108 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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 ISOMediaWriter_h_
#define ISOMediaWriter_h_
#include "ContainerWriter.h"
#include "nsAutoPtr.h"
#include "nsIRunnable.h"
namespace mozilla {
class ISOControl;
class FragmentBuffer;
class ISOMediaWriter : public ContainerWriter
{
public:
// Generate an fragmented MP4 stream, ISO/IEC 14496-12.
// Brand names in 'ftyp' box are 'isom' and 'mp42'.
const static uint32_t TYPE_FRAG_MP4 = 1 << 0;
// Generate an fragmented 3GP stream, 3GPP TS 26.244,
// '5.4.3 Basic profile'.
// Brand names in 'ftyp' box are '3gp9' and 'isom'.
const static uint32_t TYPE_FRAG_3GP = 1 << 1;
// Generate an fragmented 3G2 stream, 3GPP2 C.S0050-B
// Brand names in 'ftyp' box are '3g2c' and 'isom'
const static uint32_t TYPE_FRAG_3G2 = 1 << 2;
// aType is the combination of CREATE_AUDIO_TRACK and CREATE_VIDEO_TRACK.
// It is a hint to muxer that the output streaming contains audio, video
// or both.
//
// aHint is one of the value in TYPE_XXXXXXXX. It is a hint to muxer what kind
// of ISO format should be generated.
ISOMediaWriter(uint32_t aType, uint32_t aHint = TYPE_FRAG_MP4);
~ISOMediaWriter();
// ContainerWriter methods
nsresult WriteEncodedTrack(const EncodedFrameContainer &aData,
uint32_t aFlags = 0) override;
nsresult GetContainerData(nsTArray<nsTArray<uint8_t>>* aOutputBufs,
uint32_t aFlags = 0) override;
nsresult SetMetadata(TrackMetadataBase* aMetadata) override;
protected:
/**
* The state of each state will generate one or more blob.
* Each blob will be a moov, moof, moof... until receiving EOS.
* The generated sequence is:
*
* moov -> moof -> moof -> ... -> moof -> moof
*
* Following is the details of each state.
* MUXING_HEAD:
* It collects the metadata to generate a moov. The state transits to
* MUXING_HEAD after output moov blob.
*
* MUXING_FRAG:
* It collects enough audio/video data to generate a fragment blob. This
* will be repeated until END_OF_STREAM and then transiting to MUXING_DONE.
*
* MUXING_DONE:
* End of ISOMediaWriter life cycle.
*/
enum MuxState {
MUXING_HEAD,
MUXING_FRAG,
MUXING_DONE,
};
private:
nsresult RunState();
// True if one of following conditions hold:
// 1. Audio/Video accumulates enough data to generate a moof.
// 2. Get EOS signal.
// aEOS will be assigned to true if it gets EOS signal.
bool ReadyToRunState(bool& aEOS);
// The main class to generate and iso box. Its life time is same as
// ISOMediaWriter and deleted only if ISOMediaWriter is destroyed.
nsAutoPtr<ISOControl> mControl;
// Buffers to keep audio/video data frames, they are created when metadata is
// received. Only one instance for each media type is allowed and they will be
// deleted only if ISOMediaWriter is destroyed.
nsAutoPtr<FragmentBuffer> mAudioFragmentBuffer;
nsAutoPtr<FragmentBuffer> mVideoFragmentBuffer;
MuxState mState;
// A flag to indicate the output buffer is ready to blob out.
bool mBlobReady;
// Combination of Audio_Track or Video_Track.
uint32_t mType;
};
} // namespace mozilla
#endif // ISOMediaWriter_h_

Просмотреть файл

@ -1,131 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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 ISOTrackMetadata_h_
#define ISOTrackMetadata_h_
#include "TrackMetadataBase.h"
namespace mozilla {
class AACTrackMetadata : public AudioTrackMetadata {
public:
// AudioTrackMetadata members
uint32_t GetAudioFrameDuration() override { return mFrameDuration; }
uint32_t GetAudioFrameSize() override { return mFrameSize; }
uint32_t GetAudioSampleRate() override { return mSampleRate; }
uint32_t GetAudioChannels() override { return mChannels; }
// TrackMetadataBase member
MetadataKind GetKind() const override { return METADATA_AAC; }
// AACTrackMetadata members
AACTrackMetadata()
: mSampleRate(0)
, mFrameDuration(0)
, mFrameSize(0)
, mChannels(0) {
MOZ_COUNT_CTOR(AACTrackMetadata);
}
~AACTrackMetadata() { MOZ_COUNT_DTOR(AACTrackMetadata); }
uint32_t mSampleRate; // From 14496-3 table 1.16, it could be 7350 ~ 96000.
uint32_t mFrameDuration; // Audio frame duration based on SampleRate.
uint32_t mFrameSize; // Audio frame size, 0 is variant size.
uint32_t mChannels; // Channel number, it should be 1 or 2.
};
// AVC clock rate is 90k Hz.
#define AVC_CLOCK_RATE 90000
class AVCTrackMetadata : public VideoTrackMetadata {
public:
// VideoTrackMetadata members
uint32_t GetVideoHeight() override { return mHeight; }
uint32_t GetVideoWidth() override {return mWidth; }
uint32_t GetVideoDisplayHeight() override { return mDisplayHeight; }
uint32_t GetVideoDisplayWidth() override { return mDisplayWidth; }
uint32_t GetVideoClockRate() override { return AVC_CLOCK_RATE; }
uint32_t GetVideoFrameRate() override { return mFrameRate; }
// TrackMetadataBase member
MetadataKind GetKind() const override { return METADATA_AVC; }
// AVCTrackMetadata
AVCTrackMetadata()
: mHeight(0)
, mWidth(0)
, mDisplayHeight(0)
, mDisplayWidth(0)
, mFrameRate(0) {
MOZ_COUNT_CTOR(AVCTrackMetadata);
}
~AVCTrackMetadata() { MOZ_COUNT_DTOR(AVCTrackMetadata); }
uint32_t mHeight;
uint32_t mWidth;
uint32_t mDisplayHeight;
uint32_t mDisplayWidth;
uint32_t mFrameRate; // frames per second
};
// AMR sample rate is 8000 samples/s.
#define AMR_SAMPLE_RATE 8000
// Channel number is always 1.
#define AMR_CHANNELS 1
// AMR speech codec, 3GPP TS 26.071. Encoder and continer support AMR-NB only
// currently.
class AMRTrackMetadata : public AudioTrackMetadata {
public:
// AudioTrackMetadata members
//
// The number of sample sets generates by encoder is variant. So the
// frame duration and frame size are both 0.
uint32_t GetAudioFrameDuration() override { return 0; }
uint32_t GetAudioFrameSize() override { return 0; }
uint32_t GetAudioSampleRate() override { return AMR_SAMPLE_RATE; }
uint32_t GetAudioChannels() override { return AMR_CHANNELS; }
// TrackMetadataBase member
MetadataKind GetKind() const override { return METADATA_AMR; }
// AMRTrackMetadata members
AMRTrackMetadata() { MOZ_COUNT_CTOR(AMRTrackMetadata); }
~AMRTrackMetadata() { MOZ_COUNT_DTOR(AMRTrackMetadata); }
};
// EVRC sample rate is 8000 samples/s.
#define EVRC_SAMPLE_RATE 8000
class EVRCTrackMetadata : public AudioTrackMetadata {
public:
// AudioTrackMetadata members
//
// The number of sample sets generates by encoder is variant. So the
// frame duration and frame size are both 0.
uint32_t GetAudioFrameDuration() override { return 0; }
uint32_t GetAudioFrameSize() override { return 0; }
uint32_t GetAudioSampleRate() override { return EVRC_SAMPLE_RATE; }
uint32_t GetAudioChannels() override { return mChannels; }
// TrackMetadataBase member
MetadataKind GetKind() const override { return METADATA_EVRC; }
// EVRCTrackMetadata members
EVRCTrackMetadata()
: mChannels(0) {
MOZ_COUNT_CTOR(EVRCTrackMetadata);
}
~EVRCTrackMetadata() { MOZ_COUNT_DTOR(EVRCTrackMetadata); }
uint32_t mChannels; // Channel number, it should be 1 or 2.
};
}
#endif // ISOTrackMetadata_h_

Просмотреть файл

@ -1,138 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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/. */
#include <climits>
#include "ISOControl.h"
#include "ISOMediaBoxes.h"
#include "MP4ESDS.h"
namespace mozilla {
nsresult
MP4AudioSampleEntry::Generate(uint32_t* aBoxSize)
{
uint32_t box_size;
nsresult rv = es->Generate(&box_size);
NS_ENSURE_SUCCESS(rv, rv);
size += box_size;
*aBoxSize = size;
return NS_OK;
}
nsresult
MP4AudioSampleEntry::Write()
{
BoxSizeChecker checker(mControl, size);
nsresult rv;
rv = AudioSampleEntry::Write();
NS_ENSURE_SUCCESS(rv, rv);
rv = es->Write();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
MP4AudioSampleEntry::MP4AudioSampleEntry(ISOControl* aControl)
: AudioSampleEntry(NS_LITERAL_CSTRING("mp4a"), aControl)
{
es = new ESDBox(aControl);
MOZ_COUNT_CTOR(MP4AudioSampleEntry);
}
MP4AudioSampleEntry::~MP4AudioSampleEntry()
{
MOZ_COUNT_DTOR(MP4AudioSampleEntry);
}
nsresult
ESDBox::Generate(uint32_t* aBoxSize)
{
uint32_t box_size;
es_descriptor->Generate(&box_size);
size += box_size;
*aBoxSize = size;
return NS_OK;
}
nsresult
ESDBox::Write()
{
WRITE_FULLBOX(mControl, size)
es_descriptor->Write();
return NS_OK;
}
ESDBox::ESDBox(ISOControl* aControl)
: FullBox(NS_LITERAL_CSTRING("esds"), 0, 0, aControl)
{
es_descriptor = new ES_Descriptor(aControl);
MOZ_COUNT_CTOR(ESDBox);
}
ESDBox::~ESDBox()
{
MOZ_COUNT_DTOR(ESDBox);
}
nsresult
ES_Descriptor::Find(const nsACString& aType,
nsTArray<RefPtr<MuxerOperation>>& aOperations)
{
// ES_Descriptor is not a real ISOMediaBox, so we return nothing here.
return NS_OK;
}
nsresult
ES_Descriptor::Write()
{
mControl->Write(tag);
mControl->Write(length);
mControl->Write(ES_ID);
mControl->WriteBits(streamDependenceFlag.to_ulong(), streamDependenceFlag.size());
mControl->WriteBits(URL_Flag.to_ulong(), URL_Flag.size());
mControl->WriteBits(reserved.to_ulong(), reserved.size());
mControl->WriteBits(streamPriority.to_ulong(), streamPriority.size());
mControl->Write(DecodeSpecificInfo.Elements(), DecodeSpecificInfo.Length());
return NS_OK;
}
nsresult
ES_Descriptor::Generate(uint32_t* aBoxSize)
{
nsresult rv;
// 14496-1 '8.3.4 DecoderConfigDescriptor'
// 14496-1 '10.2.3 SL Packet Header Configuration'
FragmentBuffer* frag = mControl->GetFragment(Audio_Track);
rv = frag->GetCSD(DecodeSpecificInfo);
NS_ENSURE_SUCCESS(rv, rv);
length = sizeof(ES_ID) + 1;
length += DecodeSpecificInfo.Length();
*aBoxSize = sizeof(tag) + sizeof(length) + length;
return NS_OK;
}
ES_Descriptor::ES_Descriptor(ISOControl* aControl)
: tag(ESDescrTag)
, length(0)
, ES_ID(0)
, streamDependenceFlag(0)
, URL_Flag(0)
, reserved(0)
, streamPriority(0)
, mControl(aControl)
{
MOZ_COUNT_CTOR(ES_Descriptor);
}
ES_Descriptor::~ES_Descriptor()
{
MOZ_COUNT_DTOR(ES_Descriptor);
}
}

Просмотреть файл

@ -1,87 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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 MP4ESDS_h_
#define MP4ESDS_h_
#include "nsTArray.h"
#include "MuxerOperation.h"
namespace mozilla {
class ISOControl;
/**
* ESDS tag
*/
#define ESDescrTag 0x03
/**
* 14496-1 '8.3.3 ES_Descriptor'.
* It will get DecoderConfigDescriptor and SLConfigDescriptor from
* AAC CSD data.
*/
class ES_Descriptor : public MuxerOperation {
public:
// ISO BMFF members
uint8_t tag; // ESDescrTag
uint8_t length;
uint16_t ES_ID;
std::bitset<1> streamDependenceFlag;
std::bitset<1> URL_Flag;
std::bitset<1> reserved;
std::bitset<5> streamPriority;
nsTArray<uint8_t> DecodeSpecificInfo;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
nsresult Find(const nsACString& aType,
nsTArray<RefPtr<MuxerOperation>>& aOperations) override;
// ES_Descriptor methods
ES_Descriptor(ISOControl* aControl);
~ES_Descriptor();
protected:
ISOControl* mControl;
};
// 14496-14 5.6 'Sample Description Boxes'
// Box type: 'esds'
class ESDBox : public FullBox {
public:
// ISO BMFF members
RefPtr<ES_Descriptor> es_descriptor;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// ESDBox methods
ESDBox(ISOControl* aControl);
~ESDBox();
};
// 14496-14 5.6 'Sample Description Boxes'
// Box type: 'mp4a'
class MP4AudioSampleEntry : public AudioSampleEntry {
public:
// ISO BMFF members
RefPtr<ESDBox> es;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// MP4AudioSampleEntry methods
MP4AudioSampleEntry(ISOControl* aControl);
~MP4AudioSampleEntry();
};
}
#endif // MP4ESDS_h_

Просмотреть файл

@ -1,57 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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/. */
#include "nsString.h"
#include "nsTArray.h"
#ifndef MuxerOperation_h_
#define MuxerOperation_h_
namespace mozilla {
/**
* The interface for ISO box. All Boxes inherit from this interface.
* Generate() and Write() are needed to be called to produce a complete box.
*
* Generate() will generate all the data structures and their size.
*
* Write() will write all data into muxing output stream (ISOControl actually)
* and update the data which can't be known at Generate() (for example, the
* offset of the video data in mp4 file).
*
* ISO base media format is composed of several container boxes and the contained
* boxes. The container boxes hold a list of MuxerOperation which is implemented
* by contained boxes. The contained boxes will be called via the list.
* For example:
* MovieBox (container) ---> boxes (array of MuxerOperation)
* |---> MovieHeaderBox (full box)
* |---> TrakBox (container)
* |---> MovieExtendsBox (container)
*
* The complete box structure can be found at 14496-12 E.2 "Theisombrand".
*/
class MuxerOperation {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MuxerOperation)
// Generate data of this box and its contained box, and calculate box size.
virtual nsresult Generate(uint32_t* aBoxSize) = 0;
// Write data to stream.
virtual nsresult Write() = 0;
// Find the box type via its name (name is the box type defined in 14496-12;
// for example, 'moov' is the name of MovieBox).
// It can only look child boxes including itself and the box in the boxes
// list if exists. It can't look parent boxes.
virtual nsresult Find(const nsACString& aType,
nsTArray<RefPtr<MuxerOperation>>& aOperations) = 0;
protected:
virtual ~MuxerOperation() {}
};
}
#endif

Просмотреть файл

@ -1,22 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS += [
'ISOMediaWriter.h',
'ISOTrackMetadata.h',
]
UNIFIED_SOURCES += [
'AMRBox.cpp',
'AVCBox.cpp',
'EVRCBox.cpp',
'ISOControl.cpp',
'ISOMediaBoxes.cpp',
'ISOMediaWriter.cpp',
'MP4ESDS.cpp',
]
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -1,668 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#include "GonkOmxPlatformLayer.h"
#include <binder/MemoryDealer.h>
#include <cutils/properties.h>
#include <media/IOMX.h>
#include <media/stagefright/MediaCodecList.h>
#include <utils/List.h>
#include "mozilla/Monitor.h"
#include "mozilla/layers/TextureClient.h"
#include "mozilla/layers/GrallocTextureClient.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/TextureClientRecycleAllocator.h"
#include "ImageContainer.h"
#include "MediaInfo.h"
#include "OmxDataDecoder.h"
#ifdef LOG
#undef LOG
#endif
#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("GonkOmxPlatformLayer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
#define CHECK_ERR(err) \
if (err != OK) { \
LOG("error %d at %s", err, __func__); \
return NS_ERROR_FAILURE; \
} \
// Android proprietary value.
#define ANDROID_OMX_VIDEO_CodingVP8 (static_cast<OMX_VIDEO_CODINGTYPE>(9))
using namespace android;
namespace mozilla {
// In Gonk, the software component name has prefix "OMX.google". It needs to
// have a way to use hardware codec first.
bool IsSoftwareCodec(const char* aComponentName)
{
nsAutoCString str(aComponentName);
return (str.Find(NS_LITERAL_CSTRING("OMX.google.")) == -1 ? false : true);
}
bool IsInEmulator()
{
char propQemu[PROPERTY_VALUE_MAX];
property_get("ro.kernel.qemu", propQemu, "");
return !strncmp(propQemu, "1", 1);
}
class GonkOmxObserver : public BnOMXObserver {
public:
void onMessage(const omx_message& aMsg)
{
switch (aMsg.type) {
case omx_message::EVENT:
{
sp<GonkOmxObserver> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, aMsg] () {
if (self->mClient && self->mClient->Event(aMsg.u.event_data.event,
aMsg.u.event_data.data1,
aMsg.u.event_data.data2))
{
return;
}
});
mTaskQueue->Dispatch(r.forget());
break;
}
case omx_message::EMPTY_BUFFER_DONE:
{
sp<GonkOmxObserver> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, aMsg] () {
if (!self->mPromiseLayer) {
return;
}
BufferData::BufferID id = (BufferData::BufferID)aMsg.u.buffer_data.buffer;
self->mPromiseLayer->EmptyFillBufferDone(OMX_DirInput, id);
});
mTaskQueue->Dispatch(r.forget());
break;
}
case omx_message::FILL_BUFFER_DONE:
{
sp<GonkOmxObserver> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, aMsg] () {
if (!self->mPromiseLayer) {
return;
}
// TODO: these codes look a little ugly, it'd be better to improve them.
RefPtr<BufferData> buf;
BufferData::BufferID id = (BufferData::BufferID)aMsg.u.extended_buffer_data.buffer;
buf = self->mPromiseLayer->FindAndRemoveBufferHolder(OMX_DirOutput, id);
MOZ_RELEASE_ASSERT(buf);
GonkBufferData* gonkBuffer = static_cast<GonkBufferData*>(buf.get());
// Copy the critical information to local buffer.
if (gonkBuffer->IsLocalBuffer()) {
gonkBuffer->mBuffer->nOffset = aMsg.u.extended_buffer_data.range_offset;
gonkBuffer->mBuffer->nFilledLen = aMsg.u.extended_buffer_data.range_length;
gonkBuffer->mBuffer->nFlags = aMsg.u.extended_buffer_data.flags;
gonkBuffer->mBuffer->nTimeStamp = aMsg.u.extended_buffer_data.timestamp;
}
self->mPromiseLayer->EmptyFillBufferDone(OMX_DirOutput, buf);
});
mTaskQueue->Dispatch(r.forget());
break;
}
default:
{
LOG("Unhandle event %d", aMsg.type);
}
}
}
void Shutdown()
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
mPromiseLayer = nullptr;
mClient = nullptr;
}
GonkOmxObserver(TaskQueue* aTaskQueue, OmxPromiseLayer* aPromiseLayer, OmxDataDecoder* aDataDecoder)
: mTaskQueue(aTaskQueue)
, mPromiseLayer(aPromiseLayer)
, mClient(aDataDecoder)
{
}
protected:
RefPtr<TaskQueue> mTaskQueue;
// TODO:
// we should combine both event handlers into one. And we should provide
// an unified way for event handling in OmxPlatformLayer class.
RefPtr<OmxPromiseLayer> mPromiseLayer;
RefPtr<OmxDataDecoder> mClient;
};
// This class allocates Gralloc buffer and manages TextureClient's recycle.
class GonkTextureClientRecycleHandler : public layers::ITextureClientRecycleAllocator
{
typedef MozPromise<layers::TextureClient*, nsresult, /* IsExclusive = */ true> TextureClientRecyclePromise;
public:
GonkTextureClientRecycleHandler(OMX_VIDEO_PORTDEFINITIONTYPE& aDef)
: ITextureClientRecycleAllocator()
, mMonitor("GonkTextureClientRecycleHandler")
{
RefPtr<layers::ImageBridgeChild> bridge = layers::ImageBridgeChild::GetSingleton();
// Allocate Gralloc texture memory.
layers::GrallocTextureData* textureData =
layers::GrallocTextureData::Create(gfx::IntSize(aDef.nFrameWidth, aDef.nFrameHeight),
aDef.eColorFormat,
gfx::BackendType::NONE,
GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_READ_OFTEN,
bridge);
mGraphBuffer = textureData->GetGraphicBuffer();
MOZ_ASSERT(mGraphBuffer.get());
mTextureClient =
layers::TextureClient::CreateWithData(textureData,
layers::TextureFlags::DEALLOCATE_CLIENT | layers::TextureFlags::RECYCLE,
bridge);
MOZ_ASSERT(mTextureClient);
mPromise.SetMonitor(&mMonitor);
}
RefPtr<TextureClientRecyclePromise> WaitforRecycle()
{
MonitorAutoLock lock(mMonitor);
MOZ_ASSERT(!!mGraphBuffer.get());
mTextureClient->SetRecycleAllocator(this);
return mPromise.Ensure(__func__);
}
// DO NOT use smart pointer to receive TextureClient; otherwise it will
// distrupt the reference count.
layers::TextureClient* GetTextureClient()
{
return mTextureClient;
}
GraphicBuffer* GetGraphicBuffer()
{
MonitorAutoLock lock(mMonitor);
return mGraphBuffer.get();
}
// This function is called from layers thread.
void RecycleTextureClient(layers::TextureClient* aClient) override
{
MOZ_ASSERT(mTextureClient == aClient);
// Clearing the recycle allocator drops a reference, so make sure we stay alive
// for the duration of this function.
RefPtr<GonkTextureClientRecycleHandler> kungFuDeathGrip(this);
aClient->SetRecycleAllocator(nullptr);
{
MonitorAutoLock lock(mMonitor);
mPromise.ResolveIfExists(mTextureClient, __func__);
}
}
void Shutdown()
{
MonitorAutoLock lock(mMonitor);
mPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
// DO NOT clear TextureClient here.
// The ref count could be 1 and RecycleCallback will be called if we clear
// the ref count here. That breaks the whole mechanism. (RecycleCallback
// should be called from layers)
mGraphBuffer = nullptr;
}
private:
// Because TextureClient calls RecycleCallbackl when ref count is 1, so we
// should hold only one reference here and use raw pointer when out of this
// class.
RefPtr<layers::TextureClient> mTextureClient;
// It is protected by mMonitor.
sp<android::GraphicBuffer> mGraphBuffer;
// It is protected by mMonitor.
MozPromiseHolder<TextureClientRecyclePromise> mPromise;
Monitor mMonitor;
};
GonkBufferData::GonkBufferData(bool aLiveInLocal,
GonkOmxPlatformLayer* aGonkPlatformLayer)
: BufferData(nullptr)
, mId(0)
, mGonkPlatformLayer(aGonkPlatformLayer)
{
if (!aLiveInLocal) {
mMirrorBuffer = new OMX_BUFFERHEADERTYPE;
PodZero(mMirrorBuffer.get());
mBuffer = mMirrorBuffer.get();
}
}
void
GonkBufferData::ReleaseBuffer()
{
if (mTextureClientRecycleHandler) {
mTextureClientRecycleHandler->Shutdown();
mTextureClientRecycleHandler = nullptr;
}
}
nsresult
GonkBufferData::InitSharedMemory(android::IMemory* aMemory)
{
MOZ_RELEASE_ASSERT(mMirrorBuffer.get());
// aMemory is a IPC memory, it is safe to use it here.
mBuffer->pBuffer = (OMX_U8*)aMemory->pointer();
mBuffer->nAllocLen = aMemory->size();
return NS_OK;
}
nsresult
GonkBufferData::InitLocalBuffer(IOMX::buffer_id aId)
{
MOZ_RELEASE_ASSERT(!mMirrorBuffer.get());
mBuffer = (OMX_BUFFERHEADERTYPE*)aId;
return NS_OK;
}
nsresult
GonkBufferData::InitGraphicBuffer(OMX_VIDEO_PORTDEFINITIONTYPE& aDef)
{
mTextureClientRecycleHandler = new GonkTextureClientRecycleHandler(aDef);
if (!mTextureClientRecycleHandler->GetGraphicBuffer()) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
already_AddRefed<MediaData>
GonkBufferData::GetPlatformMediaData()
{
if (mGonkPlatformLayer->GetTrackInfo()->GetAsAudioInfo()) {
// This is audio decoding.
return nullptr;
}
if (!mTextureClientRecycleHandler) {
// There is no GraphicBuffer, it should fallback to normal YUV420 VideoData.
return nullptr;
}
VideoInfo info(*mGonkPlatformLayer->GetTrackInfo()->GetAsVideoInfo());
RefPtr<VideoData> data =
VideoData::CreateAndCopyIntoTextureClient(info,
0,
mBuffer->nTimeStamp,
1,
mTextureClientRecycleHandler->GetTextureClient(),
false,
0,
info.ImageRect());
LOG("%p, disp width %d, height %d, pic width %d, height %d, time %ld",
this, info.mDisplay.width, info.mDisplay.height,
info.mImage.width, info.mImage.height, mBuffer->nTimeStamp);
// Get TextureClient Promise here to wait for resolved.
RefPtr<GonkBufferData> self(this);
mTextureClientRecycleHandler->WaitforRecycle()
->Then(mGonkPlatformLayer->GetTaskQueue(), __func__,
[self] () {
self->mPromise.ResolveIfExists(self, __func__);
},
[self] () {
OmxBufferFailureHolder failure(OMX_ErrorUndefined, self);
self->mPromise.RejectIfExists(failure, __func__);
});
return data.forget();
}
GonkOmxPlatformLayer::GonkOmxPlatformLayer(OmxDataDecoder* aDataDecoder,
OmxPromiseLayer* aPromiseLayer,
TaskQueue* aTaskQueue,
layers::ImageContainer* aImageContainer)
: mTaskQueue(aTaskQueue)
, mImageContainer(aImageContainer)
, mNode(0)
{
mOmxObserver = new GonkOmxObserver(mTaskQueue, aPromiseLayer, aDataDecoder);
}
nsresult
GonkOmxPlatformLayer::AllocateOmxBuffer(OMX_DIRTYPE aType,
BUFFERLIST* aBufferList)
{
MOZ_ASSERT(!mMemoryDealer[aType].get());
// Get port definition.
OMX_PARAM_PORTDEFINITIONTYPE def;
nsTArray<uint32_t> portindex;
GetPortIndices(portindex);
for (auto idx : portindex) {
InitOmxParameter(&def);
def.nPortIndex = idx;
OMX_ERRORTYPE err = GetParameter(OMX_IndexParamPortDefinition,
&def,
sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
if (err != OMX_ErrorNone) {
return NS_ERROR_FAILURE;
} else if (def.eDir == aType) {
LOG("Get OMX_IndexParamPortDefinition: port: %d, type: %d", def.nPortIndex, def.eDir);
break;
}
}
size_t t = 0;
// Configure video output GraphicBuffer for video decoding acceleration.
bool useGralloc = false;
if (aType == OMX_DirOutput && mQuirks.test(kRequiresAllocateBufferOnOutputPorts) &&
(def.eDomain == OMX_PortDomainVideo)) {
if (NS_FAILED(EnableOmxGraphicBufferPort(def))) {
return NS_ERROR_FAILURE;
}
LOG("Enable OMX GraphicBuffer port, number %d, width %d, height %d", def.nBufferCountActual,
def.format.video.nFrameWidth, def.format.video.nFrameHeight);
useGralloc = true;
t = 1024; // MemoryDealer doesn't like 0, it's just for MemoryDealer happy.
} else {
t = def.nBufferCountActual * def.nBufferSize;
LOG("Buffer count %d, buffer size %d", def.nBufferCountActual, def.nBufferSize);
}
bool liveinlocal = mOmx->livesLocally(mNode, getpid());
// MemoryDealer is a IPC buffer allocator in Gonk because IOMX is actually
// lives in mediaserver.
mMemoryDealer[aType] = new MemoryDealer(t, "Gecko-OMX");
for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
RefPtr<GonkBufferData> buffer;
IOMX::buffer_id bufferID;
status_t st;
nsresult rv;
buffer = new GonkBufferData(liveinlocal, this);
if (useGralloc) {
// Buffer is lived remotely. Use GraphicBuffer for decoded video frame display.
rv = buffer->InitGraphicBuffer(def.format.video);
NS_ENSURE_SUCCESS(rv, rv);
st = mOmx->useGraphicBuffer(mNode,
def.nPortIndex,
buffer->mTextureClientRecycleHandler->GetGraphicBuffer(),
&bufferID);
CHECK_ERR(st);
} else {
sp<IMemory> mem = mMemoryDealer[aType]->allocate(def.nBufferSize);
MOZ_ASSERT(mem.get());
if ((mQuirks.test(kRequiresAllocateBufferOnInputPorts) && aType == OMX_DirInput) ||
(mQuirks.test(kRequiresAllocateBufferOnOutputPorts) && aType == OMX_DirOutput)) {
// Buffer is lived remotely. We allocate a local OMX_BUFFERHEADERTYPE
// as the mirror of the remote OMX_BUFFERHEADERTYPE.
st = mOmx->allocateBufferWithBackup(mNode, aType, mem, &bufferID);
CHECK_ERR(st);
rv = buffer->InitSharedMemory(mem.get());
NS_ENSURE_SUCCESS(rv, rv);
} else {
// Buffer is lived locally, bufferID is the actually OMX_BUFFERHEADERTYPE
// pointer.
st = mOmx->useBuffer(mNode, aType, mem, &bufferID);
CHECK_ERR(st);
rv = buffer->InitLocalBuffer(bufferID);
NS_ENSURE_SUCCESS(rv, rv);
}
}
rv = buffer->SetBufferId(bufferID);
NS_ENSURE_SUCCESS(rv, rv);
aBufferList->AppendElement(buffer);
}
return NS_OK;
}
nsresult
GonkOmxPlatformLayer::ReleaseOmxBuffer(OMX_DIRTYPE aType,
BUFFERLIST* aBufferList)
{
status_t st;
uint32_t len = aBufferList->Length();
for (uint32_t i = 0; i < len; i++) {
GonkBufferData* buffer = static_cast<GonkBufferData*>(aBufferList->ElementAt(i).get());
IOMX::buffer_id id = (OMX_BUFFERHEADERTYPE*) buffer->ID();
st = mOmx->freeBuffer(mNode, aType, id);
if (st != OK) {
return NS_ERROR_FAILURE;
}
buffer->ReleaseBuffer();
}
aBufferList->Clear();
mMemoryDealer[aType].clear();
return NS_OK;
}
nsresult
GonkOmxPlatformLayer::EnableOmxGraphicBufferPort(OMX_PARAM_PORTDEFINITIONTYPE& aDef)
{
status_t st;
st = mOmx->enableGraphicBuffers(mNode, aDef.nPortIndex, OMX_TRUE);
CHECK_ERR(st);
return NS_OK;
}
OMX_ERRORTYPE
GonkOmxPlatformLayer::GetState(OMX_STATETYPE* aType)
{
return (OMX_ERRORTYPE)mOmx->getState(mNode, aType);
}
OMX_ERRORTYPE
GonkOmxPlatformLayer::GetParameter(OMX_INDEXTYPE aParamIndex,
OMX_PTR aComponentParameterStructure,
OMX_U32 aComponentParameterSize)
{
return (OMX_ERRORTYPE)mOmx->getParameter(mNode,
aParamIndex,
aComponentParameterStructure,
aComponentParameterSize);
}
OMX_ERRORTYPE
GonkOmxPlatformLayer::SetParameter(OMX_INDEXTYPE aParamIndex,
OMX_PTR aComponentParameterStructure,
OMX_U32 aComponentParameterSize)
{
return (OMX_ERRORTYPE)mOmx->setParameter(mNode,
aParamIndex,
aComponentParameterStructure,
aComponentParameterSize);
}
nsresult
GonkOmxPlatformLayer::Shutdown()
{
mOmx->freeNode(mNode);
mOmxObserver->Shutdown();
mOmxObserver = nullptr;
mOmxClient.disconnect();
return NS_OK;
}
OMX_ERRORTYPE
GonkOmxPlatformLayer::InitOmxToStateLoaded(const TrackInfo* aInfo)
{
mInfo = aInfo;
status_t err = mOmxClient.connect();
if (err != OK) {
return OMX_ErrorUndefined;
}
mOmx = mOmxClient.interface();
if (!mOmx.get()) {
return OMX_ErrorUndefined;
}
LOG("find componenet for mime type %s", mInfo->mMimeType.Data());
nsTArray<ComponentInfo> components;
if (FindComponents(mInfo->mMimeType, &components)) {
for (auto comp : components) {
if (LoadComponent(comp)) {
return OMX_ErrorNone;
}
}
}
LOG("no component is loaded");
return OMX_ErrorUndefined;
}
OMX_ERRORTYPE
GonkOmxPlatformLayer::EmptyThisBuffer(BufferData* aData)
{
return (OMX_ERRORTYPE)mOmx->emptyBuffer(mNode,
(IOMX::buffer_id)aData->ID(),
aData->mBuffer->nOffset,
aData->mBuffer->nFilledLen,
aData->mBuffer->nFlags,
aData->mBuffer->nTimeStamp);
}
OMX_ERRORTYPE
GonkOmxPlatformLayer::FillThisBuffer(BufferData* aData)
{
return (OMX_ERRORTYPE)mOmx->fillBuffer(mNode, (IOMX::buffer_id)aData->ID());
}
OMX_ERRORTYPE
GonkOmxPlatformLayer::SendCommand(OMX_COMMANDTYPE aCmd,
OMX_U32 aParam1,
OMX_PTR aCmdData)
{
return (OMX_ERRORTYPE)mOmx->sendCommand(mNode, aCmd, aParam1);
}
bool
GonkOmxPlatformLayer::LoadComponent(const ComponentInfo& aComponent)
{
status_t err = mOmx->allocateNode(aComponent.mName, mOmxObserver, &mNode);
if (err == OK) {
mQuirks = aComponent.mQuirks;
LOG("Load OpenMax component %s, alloc input %d, alloc output %d, live locally %d",
aComponent.mName, mQuirks.test(kRequiresAllocateBufferOnInputPorts),
mQuirks.test(kRequiresAllocateBufferOnOutputPorts),
mOmx->livesLocally(mNode, getpid()));
return true;
}
return false;
}
layers::ImageContainer*
GonkOmxPlatformLayer::GetImageContainer()
{
return mImageContainer;
}
const TrackInfo*
GonkOmxPlatformLayer::GetTrackInfo()
{
return mInfo;
}
bool
GonkOmxPlatformLayer::FindComponents(const nsACString& aMimeType,
nsTArray<ComponentInfo>* aComponents)
{
static const MediaCodecList* codecs = MediaCodecList::getInstance();
bool useHardwareCodecOnly = false;
// H264 and H263 has different profiles, software codec doesn't support high profile.
// So we use hardware codec only.
if (!IsInEmulator() &&
(aMimeType.EqualsLiteral("video/avc") ||
aMimeType.EqualsLiteral("video/mp4") ||
aMimeType.EqualsLiteral("video/mp4v-es") ||
aMimeType.EqualsLiteral("video/3gp"))) {
useHardwareCodecOnly = true;
}
const char* mime = aMimeType.Data();
// Translate VP8 MIME type to Android format.
if (aMimeType.EqualsLiteral("video/webm; codecs=vp8")) {
mime = "video/x-vnd.on2.vp8";
}
size_t start = 0;
bool found = false;
while (true) {
ssize_t index = codecs->findCodecByType(mime, false /* encoder */, start);
if (index < 0) {
break;
}
start = index + 1;
const char* name = codecs->getCodecName(index);
if (IsSoftwareCodec(name) && useHardwareCodecOnly) {
continue;
}
found = true;
if (!aComponents) {
continue;
}
ComponentInfo* comp = aComponents->AppendElement();
comp->mName = name;
if (codecs->codecHasQuirk(index, "requires-allocate-on-input-ports")) {
comp->mQuirks.set(kRequiresAllocateBufferOnInputPorts);
}
if (codecs->codecHasQuirk(index, "requires-allocate-on-output-ports")) {
comp->mQuirks.set(kRequiresAllocateBufferOnOutputPorts);
}
}
return found;
}
OMX_VIDEO_CODINGTYPE
GonkOmxPlatformLayer::CompressionFormat()
{
MOZ_ASSERT(mInfo);
return mInfo->mMimeType.EqualsLiteral("video/webm; codecs=vp8") ?
ANDROID_OMX_VIDEO_CodingVP8 : OmxPlatformLayer::CompressionFormat();
}
} // mozilla

Просмотреть файл

@ -1,205 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(GonkOmxPlatformLayer_h_)
#define GonkOmxPlatformLayer_h_
#pragma GCC visibility push(default)
#include <bitset>
#include <utils/RefBase.h>
#include <media/stagefright/OMXClient.h>
#include "nsAutoPtr.h"
#include "OMX_Component.h"
#include "OmxPlatformLayer.h"
class nsACString;
namespace android {
class IMemory;
class MemoryDealer;
}
namespace mozilla {
class GonkOmxObserver;
class GonkOmxPlatformLayer;
class GonkTextureClientRecycleHandler;
/*
* Due to Android's omx node could live in local process (client) or remote
* process (mediaserver). And there are 3 kinds of buffer in Android OMX.
*
* 1.
* When buffer is in local process, the IOMX::buffer_id is OMX_BUFFERHEADERTYPE
* pointer actually, it is safe to use it directly.
*
* 2.
* When buffer is in remote process, the OMX_BUFFERHEADERTYPE pointer is 'IN' the
* remote process. It can't be used in local process, so here it allocates a
* local OMX_BUFFERHEADERTYPE. The raw/decoded data is in the android shared
* memory, IMemory.
*
* 3.
* When buffer is in remote process for the display output port. It uses
* GraphicBuffer to accelerate the decoding and display.
*
*/
class GonkBufferData : public OmxPromiseLayer::BufferData {
protected:
virtual ~GonkBufferData() {}
public:
GonkBufferData(bool aLiveInLocal,
GonkOmxPlatformLayer* aLayer);
BufferID ID() override
{
return mId;
}
already_AddRefed<MediaData> GetPlatformMediaData() override;
bool IsLocalBuffer()
{
return !!mMirrorBuffer.get();
}
void ReleaseBuffer();
nsresult SetBufferId(android::IOMX::buffer_id aId)
{
mId = aId;
return NS_OK;
}
// The mBuffer is in local process. And aId is actually the OMX_BUFFERHEADERTYPE
// pointer. It doesn't need a mirror buffer.
nsresult InitLocalBuffer(android::IOMX::buffer_id aId);
// aMemory is an IPC based memory which will be used as the pBuffer in
// mBuffer. And the mBuffer will be the mirror OMX_BUFFERHEADERTYPE
// of the one in the remote process.
nsresult InitSharedMemory(android::IMemory* aMemory);
// GraphicBuffer is for video decoding acceleration on output port.
// Then mBuffer is the mirror OMX_BUFFERHEADERTYPE of the one in the remote
// process.
nsresult InitGraphicBuffer(OMX_VIDEO_PORTDEFINITIONTYPE& aDef);
// Android OMX uses this id to pass the buffer between OMX component and
// client.
android::IOMX::buffer_id mId;
// mMirrorBuffer are used only when the omx node is in mediaserver.
// Due to IPC problem, the mId is the OMX_BUFFERHEADERTYPE address in mediaserver.
// It can't mapping to client process, so we need a local OMX_BUFFERHEADERTYPE
// here to mirror the remote OMX_BUFFERHEADERTYPE in mediaserver.
nsAutoPtr<OMX_BUFFERHEADERTYPE> mMirrorBuffer;
// It creates GraphicBuffer and manages TextureClient.
RefPtr<GonkTextureClientRecycleHandler> mTextureClientRecycleHandler;
GonkOmxPlatformLayer* mGonkPlatformLayer;
};
class GonkOmxPlatformLayer : public OmxPlatformLayer {
public:
enum {
kRequiresAllocateBufferOnInputPorts = 0,
kRequiresAllocateBufferOnOutputPorts,
QUIRKS,
};
typedef std::bitset<QUIRKS> Quirks;
struct ComponentInfo {
const char* mName;
Quirks mQuirks;
};
GonkOmxPlatformLayer(OmxDataDecoder* aDataDecoder,
OmxPromiseLayer* aPromiseLayer,
TaskQueue* aTaskQueue,
layers::ImageContainer* aImageContainer);
nsresult AllocateOmxBuffer(OMX_DIRTYPE aType, BUFFERLIST* aBufferList) override;
nsresult ReleaseOmxBuffer(OMX_DIRTYPE aType, BUFFERLIST* aBufferList) override;
OMX_ERRORTYPE GetState(OMX_STATETYPE* aType) override;
OMX_ERRORTYPE GetParameter(OMX_INDEXTYPE aParamIndex,
OMX_PTR aComponentParameterStructure,
OMX_U32 aComponentParameterSize) override;
OMX_ERRORTYPE SetParameter(OMX_INDEXTYPE nIndex,
OMX_PTR aComponentParameterStructure,
OMX_U32 aComponentParameterSize) override;
OMX_ERRORTYPE InitOmxToStateLoaded(const TrackInfo* aInfo) override;
OMX_ERRORTYPE EmptyThisBuffer(BufferData* aData) override;
OMX_ERRORTYPE FillThisBuffer(BufferData* aData) override;
OMX_ERRORTYPE SendCommand(OMX_COMMANDTYPE aCmd,
OMX_U32 aParam1,
OMX_PTR aCmdData) override;
nsresult Shutdown() override;
static bool FindComponents(const nsACString& aMimeType,
nsTArray<ComponentInfo>* aComponents = nullptr);
// Android/QCOM decoder uses its own OMX_VIDEO_CodingVP8 definition in
// frameworks/native/media/include/openmax/OMX_Video.h, not the one defined
// in OpenMAX v1.1.2 OMX_VideoExt.h
OMX_VIDEO_CODINGTYPE CompressionFormat() override;
protected:
friend GonkBufferData;
layers::ImageContainer* GetImageContainer();
const TrackInfo* GetTrackInfo();
TaskQueue* GetTaskQueue()
{
return mTaskQueue;
}
nsresult EnableOmxGraphicBufferPort(OMX_PARAM_PORTDEFINITIONTYPE& aDef);
bool LoadComponent(const ComponentInfo& aComponent);
friend class GonkOmxObserver;
RefPtr<TaskQueue> mTaskQueue;
RefPtr<layers::ImageContainer> mImageContainer;
// OMX_DirInput is 0, OMX_DirOutput is 1.
android::sp<android::MemoryDealer> mMemoryDealer[2];
android::sp<GonkOmxObserver> mOmxObserver;
android::sp<android::IOMX> mOmx;
android::IOMX::node_id mNode;
android::OMXClient mOmxClient;
Quirks mQuirks;
};
}
#pragma GCC visibility pop
#endif // GonkOmxPlatformLayer_h_

Просмотреть файл

@ -1,655 +0,0 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* 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/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const TOPIC_INTERFACE_STATE_CHANGED = "network-interface-state-changed";
const ETHERNET_NETWORK_IFACE_PREFIX = "eth";
const DEFAULT_ETHERNET_NETWORK_IFACE = "eth0";
const INTERFACE_IPADDR_NULL = "0.0.0.0";
const INTERFACE_GATEWAY_NULL = "0.0.0.0";
const INTERFACE_PREFIX_NULL = 0;
const INTERFACE_MACADDR_NULL = "00:00:00:00:00:00";
const NETWORK_INTERFACE_UP = "up";
const NETWORK_INTERFACE_DOWN = "down";
const IP_MODE_DHCP = "dhcp";
const IP_MODE_STATIC = "static";
const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled";
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
"@mozilla.org/network/manager;1",
"nsINetworkManager");
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService",
"@mozilla.org/network/service;1",
"nsINetworkService");
let debug;
function updateDebug() {
let debugPref = false; // set default value here.
try {
debugPref = debugPref || Services.prefs.getBoolPref(PREF_NETWORK_DEBUG_ENABLED);
} catch (e) {}
if (debugPref) {
debug = function(s) {
dump("-*- EthernetManager: " + s + "\n");
};
} else {
debug = function(s) {};
}
}
updateDebug();
// nsINetworkInterface
function EthernetInterface(attr) {
this.info.state = attr.state;
this.info.type = attr.type;
this.info.name = attr.name;
this.info.ipMode = attr.ipMode;
this.info.ips = [attr.ip];
this.info.prefixLengths = [attr.prefixLength];
this.info.gateways = [attr.gateway];
this.info.dnses = attr.dnses;
this.httpProxyHost = "";
this.httpProxyPort = 0;
}
EthernetInterface.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface]),
updateConfig: function(config) {
debug("Interface " + this.info.name + " updateConfig " + JSON.stringify(config));
this.info.state = (config.state != undefined) ?
config.state : this.info.state;
this.info.ips = (config.ip != undefined) ? [config.ip] : this.info.ips;
this.info.prefixLengths = (config.prefixLength != undefined) ?
[config.prefixLength] : this.info.prefixLengths;
this.info.gateways = (config.gateway != undefined) ?
[config.gateway] : this.info.gateways;
this.info.dnses = (config.dnses != undefined) ? config.dnses : this.info.dnses;
this.httpProxyHost = (config.httpProxyHost != undefined) ?
config.httpProxyHost : this.httpProxyHost;
this.httpProxyPort = (config.httpProxyPort != undefined) ?
config.httpProxyPort : this.httpProxyPort;
this.info.ipMode = (config.ipMode != undefined) ?
config.ipMode : this.info.ipMode;
},
info: {
getAddresses: function(ips, prefixLengths) {
ips.value = this.ips.slice();
prefixLengths.value = this.prefixLengths.slice();
return this.ips.length;
},
getGateways: function(count) {
if (count) {
count.value = this.gateways.length;
}
return this.gateways.slice();
},
getDnses: function(count) {
if (count) {
count.value = this.dnses.length;
}
return this.dnses.slice();
}
}
};
// nsIEthernetManager
/*
* Network state transition diagram
*
* ---------- enable --------- connect ----------- disconnect --------------
* | Disabled | -----> | Enabled | -------> | Connected | <----------> | Disconnected |
* ---------- --------- ----------- connect --------------
* ^ | | |
* | disable | | |
* -----------------------------------------------------------------------
*/
function EthernetManager() {
debug("EthernetManager start");
// Interface list.
this.ethernetInterfaces = {};
// Used to memorize last connection information.
this.lastStaticConfig = {};
Services.obs.addObserver(this, "xpcom-shutdown");
}
EthernetManager.prototype = {
classID: Components.ID("a96441dd-36b3-4f7f-963b-2c032e28a039"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIEthernetManager]),
ethernetInterfaces: null,
lastStaticConfig: null,
observer: function(subject, topic, data) {
switch (topic) {
case "xpcom-shutdown":
debug("xpcom-shutdown");
this._shutdown();
Services.obs.removeObserver(this, "xpcom-shutdown");
break;
}
},
_shutdown: function() {
debug("Shuting down");
(function onRemove(ifnameList) {
if (!ifnameList.length) {
return;
}
let ifname = ifnameList.shift();
this.removeInterface(ifname, { notify: onRemove.bind(this, ifnameList) });
}).call(this, Object.keys(this.ethernetInterfaces));
},
get interfaceList() {
return Object.keys(this.ethernetInterfaces);
},
scan: function(callback) {
debug("Scan");
gNetworkService.getInterfaces(function(success, list) {
let ethList = [];
if (!success) {
if (callback) {
callback.notify(ethList);
}
return;
}
for (let i = 0; i < list.length; i++) {
debug("Found interface " + list[i]);
if (!list[i].startsWith(ETHERNET_NETWORK_IFACE_PREFIX)) {
continue;
}
ethList.push(list[i]);
}
if (callback) {
callback.notify(ethList);
}
});
},
addInterface: function(ifname, callback) {
debug("Add interface " + ifname);
if (!ifname || !ifname.startsWith(ETHERNET_NETWORK_IFACE_PREFIX)) {
if (callback) {
callback.notify(false, "Invalid interface.");
}
return;
}
if (this.ethernetInterfaces[ifname]) {
if (callback) {
callback.notify(true, "Interface already exists.");
}
return;
}
gNetworkService.getInterfaceConfig(ifname, function(success, result) {
if (!success) {
if (callback) {
callback.notify(false, "Netd error.");
}
return;
}
// Since the operation may still succeed with an invalid interface name,
// check the mac address as well.
if (result.macAddr == INTERFACE_MACADDR_NULL) {
if (callback) {
callback.notify(false, "Interface not found.");
}
return;
}
this.ethernetInterfaces[ifname] = new EthernetInterface({
state: result.link == NETWORK_INTERFACE_UP ?
Ci.nsINetworkInfo.NETWORK_STATE_DISABLED :
Ci.nsINetworkInfo.NETWORK_STATE_ENABLED,
name: ifname,
type: Ci.nsINetworkInfo.NETWORK_TYPE_ETHERNET,
ip: result.ip,
prefixLength: result.prefix,
ipMode: IP_MODE_DHCP
});
// Register the interface to NetworkManager.
gNetworkManager.registerNetworkInterface(this.ethernetInterfaces[ifname]);
debug("Add interface " + ifname + " succeeded with " +
JSON.stringify(this.ethernetInterfaces[ifname]));
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
},
removeInterface: function(ifname, callback) {
debug("Remove interface " + ifname);
if (!ifname || !ifname.startsWith(ETHERNET_NETWORK_IFACE_PREFIX)) {
if (callback) {
callback.notify(false, "Invalid interface.");
}
return;
}
if (!this.ethernetInterfaces[ifname]) {
if (callback) {
callback.notify(true, "Interface does not exist.");
}
return;
}
// Make sure interface is disable before removing.
this.disable(ifname, { notify: function(success, message) {
// Unregister the interface from NetworkManager and also remove it from
// the interface list.
gNetworkManager.unregisterNetworkInterface(this.ethernetInterfaces[ifname]);
delete this.ethernetInterfaces[ifname];
debug("Remove interface " + ifname + " succeeded.");
if (callback) {
callback.notify(true, "ok");
}
}.bind(this)});
},
updateInterfaceConfig: function(ifname, config, callback) {
debug("Update interface config with " + ifname);
this._ensureIfname(ifname, callback, function(iface) {
if (!config) {
if (callback) {
callback.notify(false, "No config to update.");
}
return;
}
// Network state can not be modified externally.
if (config.state) {
delete config.state;
}
let currentIpMode = iface.info.ipMode;
// Update config.
this.ethernetInterfaces[iface.info.name].updateConfig(config);
// Do not automatically re-connect if the interface is not in connected
// state.
if (iface.info.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) {
if (callback) {
callback.notify(true, "ok");
}
return;
}
let newIpMode = this.ethernetInterfaces[iface.info.name].info.ipMode;
if (newIpMode == IP_MODE_STATIC) {
this._setStaticIP(iface.info.name, callback);
return;
}
if ((currentIpMode == IP_MODE_STATIC) && (newIpMode == IP_MODE_DHCP)) {
gNetworkService.stopDhcp(iface.info.name, function(success) {
if (success) {
debug("DHCP for " + iface.info.name + " stopped.");
}
});
// Clear the current network settings before do dhcp request, otherwise
// dhcp settings could fail.
this.disconnect(iface.info.name, { notify: function(success, message) {
if (!success) {
if (callback) {
callback.notify("Disconnect failed.");
}
return;
}
this._runDhcp(iface.info.name, callback);
}.bind(this) });
return;
}
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
},
enable: function(ifname, callback) {
debug("Enable interface " + ifname);
this._ensureIfname(ifname, callback, function(iface) {
// Interface can be only enabled in the state of disabled.
if (iface.info.state != Ci.nsINetworkInfo.NETWORK_STATE_DISABLED) {
if (callback) {
callback.notify(true, "Interface already enabled.");
}
return;
}
let ips = {};
let prefixLengths = {};
iface.info.getAddresses(ips, prefixLengths);
let config = { ifname: iface.info.name,
ip: ips.value[0],
prefix: prefixLengths.value[0],
link: NETWORK_INTERFACE_UP };
gNetworkService.setInterfaceConfig(config, function(success) {
if (!success) {
if (callback) {
callback.notify(false, "Netd Error.");
}
return;
}
this.ethernetInterfaces[iface.info.name].updateConfig({
state: Ci.nsINetworkInfo.NETWORK_STATE_ENABLED
});
debug("Enable interface " + iface.info.name + " succeeded.");
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
}.bind(this));
},
disable: function(ifname, callback) {
debug("Disable interface " + ifname);
this._ensureIfname(ifname, callback, function(iface) {
if (iface.info.state == Ci.nsINetworkInfo.NETWORK_STATE_DISABLED) {
if (callback) {
callback.notify(true, "Interface already disabled.");
}
return;
}
if (iface.info.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) {
gNetworkService.stopDhcp(iface.info.name, function(success) {
if (success) {
debug("DHCP for " + iface.info.name + " stopped.");
}
});
}
let ips = {};
let prefixLengths = {};
iface.info.getAddresses(ips, prefixLengths);
let config = { ifname: iface.info.name,
ip: ips.value[0],
prefix: prefixLengths.value[0],
link: NETWORK_INTERFACE_DOWN };
gNetworkService.setInterfaceConfig(config, function(success) {
if (!success) {
if (callback) {
callback.notify(false, "Netd Error.");
}
return;
}
this.ethernetInterfaces[iface.info.name].updateConfig({
state: Ci.nsINetworkInfo.NETWORK_STATE_DISABLED
});
debug("Disable interface " + iface.info.name + " succeeded.");
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
}.bind(this));
},
connect: function(ifname, callback) {
debug("Connect interface " + ifname);
this._ensureIfname(ifname, callback, function(iface) {
// Interface can only be connected in the state of enabled or
// disconnected.
if (iface.info.state == Ci.nsINetworkInfo.NETWORK_STATE_DISABLED ||
iface.info.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) {
if (callback) {
callback.notify(true, "Interface " + ifname + " is not available or "
+ " already connected.");
}
return;
}
if (iface.info.ipMode == IP_MODE_DHCP) {
this._runDhcp(iface.info.name, callback);
return;
}
if (iface.info.ipMode == IP_MODE_STATIC) {
if (this._checkConfigNull(iface) && this.lastStaticConfig[iface.info.name]) {
debug("Connect with lastStaticConfig " +
JSON.stringify(this.lastStaticConfig[iface.info.name]));
this.ethernetInterfaces[iface.info.name].updateConfig(
this.lastStaticConfig[iface.info.name]);
}
this._setStaticIP(iface.info.name, callback);
return;
}
if (callback) {
callback.notify(false, "IP mode is wrong or not set.");
}
}.bind(this));
},
disconnect: function(ifname, callback) {
debug("Disconnect interface " + ifname);
this._ensureIfname(ifname, callback, function(iface) {
// Interface can be only disconnected in the state of connected.
if (iface.info.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) {
if (callback) {
callback.notify(true, "Interface is already disconnected");
}
return;
}
let config = { ifname: iface.info.name,
ip: INTERFACE_IPADDR_NULL,
prefix: INTERFACE_PREFIX_NULL,
link: NETWORK_INTERFACE_UP };
gNetworkService.setInterfaceConfig(config, function(success) {
if (!success) {
if (callback) {
callback.notify(false, "Netd error.");
}
return;
}
// Stop dhcp daemon.
gNetworkService.stopDhcp(iface.info.name, function(success) {
if (success) {
debug("DHCP for " + iface.info.name + " stopped.");
}
});
this.ethernetInterfaces[iface.info.name].updateConfig({
state: Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED,
ip: INTERFACE_IPADDR_NULL,
prefixLength: INTERFACE_PREFIX_NULL,
gateway: INTERFACE_GATEWAY_NULL
});
gNetworkManager.updateNetworkInterface(this.ethernetInterfaces[ifname]);
debug("Disconnect interface " + iface.info.name + " succeeded.");
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
}.bind(this));
},
_checkConfigNull: function(iface) {
let ips = {};
let prefixLengths = {};
let gateways = iface.info.getGateways();
iface.info.getAddresses(ips, prefixLengths);
if (ips.value[0] == INTERFACE_IPADDR_NULL &&
prefixLengths.value[0] == INTERFACE_PREFIX_NULL &&
gateways[0] == INTERFACE_GATEWAY_NULL) {
return true;
}
return false;
},
_ensureIfname: function(ifname, callback, func) {
// If no given ifname, use the default one.
if (!ifname) {
ifname = DEFAULT_ETHERNET_NETWORK_IFACE;
}
let iface = this.ethernetInterfaces[ifname];
if (!iface) {
if (callback) {
callback.notify(true, "Interface " + ifname + " is not available.");
}
return;
}
func.call(this, iface);
},
_runDhcp: function(ifname, callback) {
debug("runDhcp with " + ifname);
if (!this.ethernetInterfaces[ifname]) {
if (callback) {
callback.notify(false, "Invalid interface.");
}
return;
}
gNetworkService.dhcpRequest(ifname, function(success, result) {
if (!success) {
if (callback) {
callback.notify(false, "DHCP failed.");
}
return;
}
debug("DHCP succeeded with " + JSON.stringify(result));
// Clear last static network information when connecting with dhcp mode.
if (this.lastStaticConfig[ifname]) {
this.lastStaticConfig[ifname] = null;
}
this.ethernetInterfaces[ifname].updateConfig({
state: Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED,
ip: result.ipaddr_str,
gateway: result.gateway_str,
prefixLength: result.prefixLength,
dnses: [result.dns1_str, result.dns2_str]
});
gNetworkManager.updateNetworkInterface(this.ethernetInterfaces[ifname]);
debug("Connect interface " + ifname + " with DHCP succeeded.");
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
},
_setStaticIP: function(ifname, callback) {
let iface = this.ethernetInterfaces[ifname];
if (!iface) {
if (callback) {
callback.notify(false, "Invalid interface.");
}
return;
}
let ips = {};
let prefixLengths = {};
iface.info.getAddresses(ips, prefixLengths);
let config = { ifname: iface.info.name,
ip: ips.value[0],
prefix: prefixLengths.value[0],
link: NETWORK_INTERFACE_UP };
gNetworkService.setInterfaceConfig(config, function(success) {
if (!success) {
if (callback) {
callback.notify(false, "Netd Error.");
}
return;
}
// Keep the lastest static network information.
let ips = {};
let prefixLengths = {};
let gateways = iface.info.getGateways();
iface.info.getAddresses(ips, prefixLengths);
this.lastStaticConfig[iface.info.name] = {
ip: ips.value[0],
prefixLength: prefixLengths.value[0],
gateway: gateways[0]
};
this.ethernetInterfaces[ifname].updateConfig({
state: Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED,
});
gNetworkManager.updateNetworkInterface(this.ethernetInterfaces[ifname]);
debug("Connect interface " + ifname + " with static ip succeeded.");
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
},
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EthernetManager]);

Просмотреть файл

@ -1,2 +0,0 @@
component {a96441dd-36b3-4f7f-963b-2c032e28a039} EthernetManager.js
contract @mozilla.org/ethernetManager;1 {a96441dd-36b3-4f7f-963b-2c032e28a039}

Просмотреть файл

@ -1,200 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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/. */
#include "NetUtils.h"
#include <dlfcn.h>
#include <errno.h>
#include "prinit.h"
#include "mozilla/Assertions.h"
#include "nsDebug.h"
#include "SystemProperty.h"
using mozilla::system::Property;
static void* sNetUtilsLib;
static PRCallOnceType sInitNetUtilsLib;
static PRStatus
InitNetUtilsLib()
{
sNetUtilsLib = dlopen("/system/lib/libnetutils.so", RTLD_LAZY);
// We might fail to open the hardware lib. That's OK.
return PR_SUCCESS;
}
static void*
GetNetUtilsLibHandle()
{
PR_CallOnce(&sInitNetUtilsLib, InitNetUtilsLib);
return sNetUtilsLib;
}
// static
void*
NetUtils::GetSharedLibrary()
{
void* netLib = GetNetUtilsLibHandle();
if (!netLib) {
NS_WARNING("No /system/lib/libnetutils.so");
}
return netLib;
}
// static
int32_t
NetUtils::SdkVersion()
{
char propVersion[Property::VALUE_MAX_LENGTH];
Property::Get("ro.build.version.sdk", propVersion, "0");
int32_t version = strtol(propVersion, nullptr, 10);
return version;
}
DEFINE_DLFUNC(ifc_enable, int32_t, const char*)
DEFINE_DLFUNC(ifc_disable, int32_t, const char*)
DEFINE_DLFUNC(ifc_configure, int32_t, const char*, in_addr_t, uint32_t,
in_addr_t, in_addr_t, in_addr_t)
DEFINE_DLFUNC(ifc_reset_connections, int32_t, const char*, const int32_t)
DEFINE_DLFUNC(ifc_set_default_route, int32_t, const char*, in_addr_t)
DEFINE_DLFUNC(ifc_add_route, int32_t, const char*, const char*, uint32_t, const char*)
DEFINE_DLFUNC(ifc_remove_route, int32_t, const char*, const char*, uint32_t, const char*)
DEFINE_DLFUNC(ifc_remove_host_routes, int32_t, const char*)
DEFINE_DLFUNC(ifc_remove_default_route, int32_t, const char*)
DEFINE_DLFUNC(dhcp_stop, int32_t, const char*)
NetUtils::NetUtils()
{
}
int32_t NetUtils::do_ifc_enable(const char *ifname)
{
USE_DLFUNC(ifc_enable)
return ifc_enable(ifname);
}
int32_t NetUtils::do_ifc_disable(const char *ifname)
{
USE_DLFUNC(ifc_disable)
return ifc_disable(ifname);
}
int32_t NetUtils::do_ifc_configure(const char *ifname,
in_addr_t address,
uint32_t prefixLength,
in_addr_t gateway,
in_addr_t dns1,
in_addr_t dns2)
{
USE_DLFUNC(ifc_configure)
int32_t ret = ifc_configure(ifname, address, prefixLength, gateway, dns1, dns2);
return ret;
}
int32_t NetUtils::do_ifc_reset_connections(const char *ifname,
const int32_t resetMask)
{
USE_DLFUNC(ifc_reset_connections)
return ifc_reset_connections(ifname, resetMask);
}
int32_t NetUtils::do_ifc_set_default_route(const char *ifname,
in_addr_t gateway)
{
USE_DLFUNC(ifc_set_default_route)
return ifc_set_default_route(ifname, gateway);
}
int32_t NetUtils::do_ifc_add_route(const char *ifname,
const char *dst,
uint32_t prefixLength,
const char *gateway)
{
USE_DLFUNC(ifc_add_route)
return ifc_add_route(ifname, dst, prefixLength, gateway);
}
int32_t NetUtils::do_ifc_remove_route(const char *ifname,
const char *dst,
uint32_t prefixLength,
const char *gateway)
{
USE_DLFUNC(ifc_remove_route)
return ifc_remove_route(ifname, dst, prefixLength, gateway);
}
int32_t NetUtils::do_ifc_remove_host_routes(const char *ifname)
{
USE_DLFUNC(ifc_remove_host_routes)
return ifc_remove_host_routes(ifname);
}
int32_t NetUtils::do_ifc_remove_default_route(const char *ifname)
{
USE_DLFUNC(ifc_remove_default_route)
return ifc_remove_default_route(ifname);
}
int32_t NetUtils::do_dhcp_stop(const char *ifname)
{
USE_DLFUNC(dhcp_stop)
return dhcp_stop(ifname);
}
int32_t NetUtils::do_dhcp_do_request(const char *ifname,
char *ipaddr,
char *gateway,
uint32_t *prefixLength,
char *dns1,
char *dns2,
char *server,
uint32_t *lease,
char* vendorinfo)
{
int32_t ret = -1;
uint32_t sdkVersion = SdkVersion();
if (sdkVersion == 15) {
// ICS
// http://androidxref.com/4.0.4/xref/system/core/libnetutils/dhcp_utils.c#149
DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*, uint32_t*, char*, char*, char*, uint32_t*)
USE_DLFUNC(dhcp_do_request)
vendorinfo[0] = '\0';
ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns1, dns2,
server, lease);
} else if (sdkVersion == 16 || sdkVersion == 17) {
// JB 4.1 and 4.2
// http://androidxref.com/4.1.2/xref/system/core/libnetutils/dhcp_utils.c#175
// http://androidxref.com/4.2.2_r1/xref/system/core/include/netutils/dhcp.h#26
DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*, uint32_t*, char*, char*, char*, uint32_t*, char*)
USE_DLFUNC(dhcp_do_request)
ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns1, dns2,
server, lease, vendorinfo);
} else if (sdkVersion == 18) {
// JB 4.3
// http://androidxref.com/4.3_r2.1/xref/system/core/libnetutils/dhcp_utils.c#181
DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*, uint32_t*, char**, char*, uint32_t*, char*, char*)
USE_DLFUNC(dhcp_do_request)
char *dns[3] = {dns1, dns2, nullptr};
char domains[Property::VALUE_MAX_LENGTH];
ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns,
server, lease, vendorinfo, domains);
} else if (sdkVersion >= 19) {
// KitKat 4.4.X
// http://androidxref.com/4.4_r1/xref/system/core/libnetutils/dhcp_utils.c#18
// Lollipop 5.0
//http://androidxref.com/5.0.0_r2/xref/system/core/libnetutils/dhcp_utils.c#186
DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*, uint32_t*, char**, char*, uint32_t*, char*, char*, char*)
USE_DLFUNC(dhcp_do_request)
char *dns[3] = {dns1, dns2, nullptr};
char domains[Property::VALUE_MAX_LENGTH];
char mtu[Property::VALUE_MAX_LENGTH];
ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns, server, lease, vendorinfo, domains, mtu);
} else {
NS_WARNING("Unable to perform do_dhcp_request: unsupported sdk version!");
}
return ret;
}

Просмотреть файл

@ -1,75 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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/. */
/**
* Abstraction on top of the network support from libnetutils that we
* use to set up network connections.
*/
#ifndef NetUtils_h
#define NetUtils_h
#include "arpa/inet.h"
// Copied from ifc.h
#define RESET_IPV4_ADDRESSES 0x01
#define RESET_IPV6_ADDRESSES 0x02
#define RESET_ALL_ADDRESSES (RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES)
// Implements netutils functions. No need for an abstract class here since we
// only have a one sdk specific method (dhcp_do_request)
class NetUtils
{
public:
static void* GetSharedLibrary();
NetUtils();
int32_t do_ifc_enable(const char *ifname);
int32_t do_ifc_disable(const char *ifname);
int32_t do_ifc_configure(const char *ifname,
in_addr_t address,
uint32_t prefixLength,
in_addr_t gateway,
in_addr_t dns1,
in_addr_t dns2);
int32_t do_ifc_reset_connections(const char *ifname, const int32_t resetMask);
int32_t do_ifc_set_default_route(const char *ifname, in_addr_t gateway);
int32_t do_ifc_add_route(const char *ifname,
const char *dst,
uint32_t prefixLength,
const char *gateway);
int32_t do_ifc_remove_route(const char *ifname,
const char *dst,
uint32_t prefixLength,
const char *gateway);
int32_t do_ifc_remove_host_routes(const char *ifname);
int32_t do_ifc_remove_default_route(const char *ifname);
int32_t do_dhcp_stop(const char *ifname);
int32_t do_dhcp_do_request(const char *ifname,
char *ipaddr,
char *gateway,
uint32_t *prefixLength,
char *dns1,
char *dns2,
char *server,
uint32_t *lease,
char* vendorinfo);
static int32_t SdkVersion();
};
// Defines a function type with the right arguments and return type.
#define DEFINE_DLFUNC(name, ret, args...) typedef ret (*FUNC##name)(args);
// Set up a dlsymed function ready to use.
#define USE_DLFUNC(name) \
FUNC##name name = (FUNC##name) dlsym(GetSharedLibrary(), #name); \
if (!name) { \
MOZ_CRASH("Symbol not found in shared library : " #name); \
}
#endif // NetUtils_h

Просмотреть файл

@ -1,137 +0,0 @@
/* 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/. */
#include "nsISupports.idl"
[scriptable, function, uuid(2a3ad56c-edc0-439f-8aae-900b331ddf49)]
interface nsIEthernetManagerCallback : nsISupports
{
/**
* Callback function used to report the success of different operations.
*
* @param success
* Boolean value indicates the success of an operation.
* @prarm message
* Message reported in the end of operation.
*/
void notify(in boolean success, in DOMString message);
};
[scriptable, function, uuid(1746e7dd-92d4-43fa-8ef4-bc13d0b60353)]
interface nsIEthernetManagerScanCallback : nsISupports
{
/**
* Callback function used to report the result of scan function.
*
* @param list
* List of available ethernet interfaces.
*/
void notify(in jsval list);
};
/**
* An internal idl provides control to ethernet interfaces.
*/
[scriptable, uuid(81750c87-bb3b-4724-b955-834eafa53fd1)]
interface nsIEthernetManager : nsISupports
{
/**
* List of exisiting interface name.
*/
readonly attribute jsval interfaceList;
/**
* Scan available ethernet interfaces on device.
*
* @param callback
* Callback function.
*/
void scan(in nsIEthernetManagerScanCallback callback);
/**
* Add a new interface to the interface list.
*
* @param ifname
* Interface name. Should be the form of "eth*".
* @param callback
* Callback function.
*/
void addInterface(in DOMString ifname,
in nsIEthernetManagerCallback callback);
/**
* Remove an existing interface from the interface list.
*
* @param ifname
* Interface name.
* @param Callback
* Callback function.
*/
void removeInterface(in DOMString ifname,
in nsIEthernetManagerCallback callback);
/**
* Update a conifg of an existing interface in the interface list.
*
* @param ifname
* Interface name.
* @param config
* .ip: IP address.
* .prefixLength: Mask length.
* .gateway: Gateway.
* .dnses: DNS addresses.
* .httpProxyHost: HTTP proxy host.
* .httpProxyPort: HTTP proxy port.
* .ipMode: IP mode, can be 'dhcp' or 'static'.
* @param callback
* Callback function.
*/
void updateInterfaceConfig(in DOMString ifname,
in jsval config,
in nsIEthernetManagerCallback callback);
/**
* Enable networking of an existing interface in the interface list.
*
* @param ifname
* Interface name.
* @param callback
* Callback function.
*/
void enable(in DOMString ifname,
in nsIEthernetManagerCallback callback);
/**
* Disable networking of an existing interface in the interface list.
*
* @param ifname
* Interface name.
* @param callback
* Callback function.
*/
void disable(in DOMString ifname,
in nsIEthernetManagerCallback callback);
/**
* Make an existing interface connect to network.
*
* @param ifname
* Interface name.
* @param callback
* Callback function.
*/
void connect(in DOMString ifname,
in nsIEthernetManagerCallback callback);
/**
* Disconnect a connected interface in the interface list.
*
* @param ifname
* Interface name.
* @param callback
* Callback function.
*/
void disconnect(in DOMString ifname,
in nsIEthernetManagerCallback callback);
};

Просмотреть файл

@ -1,116 +0,0 @@
/* 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/. */
/* Copyright © 2015, Deutsche Telekom, Inc. */
"use strict";
this.SEUtils = {
byteArrayToHexString: function byteArrayToHexString(array) {
let hexStr = "";
let len = array ? array.length : 0;
for (let i = 0; i < len; i++) {
let hex = (array[i] & 0xff).toString(16);
hex = (hex.length === 1) ? "0" + hex : hex;
hexStr += hex;
}
return hexStr.toUpperCase();
},
hexStringToByteArray: function hexStringToByteArray(hexStr) {
if (typeof hexStr !== "string" || hexStr.length % 2 !== 0) {
return [];
}
let array = [];
for (let i = 0, len = hexStr.length; i < len; i += 2) {
array.push(parseInt(hexStr.substr(i, 2), 16));
}
return array;
},
arraysEqual: function arraysEqual(a1, a2) {
if (!a1 || !a2) {
return false;
}
if (a1.length !== a2.length) {
return false;
}
for (let i = 0, len = a1.length; i < len; i++) {
if (a1[i] !== a2[i]) {
return false;
}
}
return true;
},
ensureIsArray: function ensureIsArray(obj) {
return Array.isArray(obj) ? obj : [obj];
},
/**
* parseTLV is intended primarily to be used to parse Global Platform Device
* Technology secure element access control data.
*
* The parsed result value is an internal format only.
*
* All tags will be treated as simple Tag Length Values (TLV), (i.e. with a
* plain value, not subject to further unpacking), unless those tags are
* listed in the containerTags array.
*
* @param bytes - byte array
* @param containerTags - byte array of tags
*/
parseTLV: function parseTLV(bytes, containerTags) {
let result = {};
if (typeof bytes === "string") {
bytes = this.hexStringToByteArray(bytes);
}
if (!Array.isArray(bytes)) {
debug("Passed value is not an array nor a string.");
return null;
}
for (let pos = 0; pos < bytes.length; ) {
let tag = bytes[pos],
length = bytes[pos + 1],
value = bytes.slice(pos + 2, pos + 2 + length),
parsed = null;
// Support for 0xFF padded files (GPD 7.1.2)
if (tag === 0xFF) {
break;
}
if (containerTags.indexOf(tag) >= 0) {
parsed = this.parseTLV(value, containerTags);
} else {
parsed = value;
}
// Internal parsed format.
if (!result[tag]) {
result[tag] = parsed;
} else if (Array.isArray(result[tag])) {
result[tag].push(parsed);
} else {
result[tag] = [result[tag], parsed];
}
pos = pos + 2 + length;
}
return result;
}
};
this.EXPORTED_SYMBOLS = ["SEUtils"];

Просмотреть файл

@ -1,139 +0,0 @@
/* 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/. */
/* Copyright © 2015, Deutsche Telekom, Inc. */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SEUtils",
"resource://gre/modules/SEUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "SE", function() {
let obj = {};
Cu.import("resource://gre/modules/se_consts.js", obj);
return obj;
});
var DEBUG = SE.DEBUG_ACE;
function debug(msg) {
if (DEBUG) {
dump("ACEservice: " + msg + "\n");
}
}
/**
* Implements decision making algorithm as described in GPD specification,
* mostly in 3.1, 3.2 and 4.2.3.
*
* TODO: Bug 1137533: Implement GPAccessRulesManager APDU filters
*/
function GPAccessDecision(rules, certHash, aid) {
this.rules = rules;
this.certHash = certHash;
this.aid = aid;
}
GPAccessDecision.prototype = {
isAccessAllowed: function isAccessAllowed() {
// GPD SE Access Control v1.1, 3.4.1, Table 3-2: (Conflict resolution)
// If a specific rule allows, all other non-specific access is denied.
// Conflicting specific rules will resolve to the first Allowed == "true"
// match. Given no specific rule, the global "All" rules will determine
// access. "Some", skips further processing if access Allowed == "true".
//
// Access must be decided before the SE connector openChannel, and the
// exchangeAPDU call.
//
// NOTE: This implementation may change with the introduction of APDU
// filters.
let decision = this.rules.some(this._decideAppAccess.bind(this));
return decision;
},
_decideAppAccess: function _decideAppAccess(rule) {
let appMatched, appletMatched;
// GPD SE AC 4.2.3: Algorithm for Applying Rules
// Specific rule overrides global rule.
//
// DeviceAppID is the application hash, and the AID is SE Applet ID:
//
// GPD SE AC 4.2.3 A:
// SearchRuleFor(DeviceAppID, AID)
// GPD SE AC 4.2.3 B: If no rule fits A:
// SearchRuleFor(<AllDeviceApplications>, AID)
// GPD SE AC 4.2.3 C: If no rule fits A or B:
// SearchRuleFor(DeviceAppID, <AllSEApplications>)
// GPD SE AC 4.2.3 D: If no rule fits A, B, or C:
// SearchRuleFor(<AllDeviceApplications>, <AllSEApplications>)
// Device App
appMatched = Array.isArray(rule.application) ?
// GPD SE AC 4.2.3 A and 4.2.3 C (DeviceAppID rule)
this._appCertHashMatches(rule.application) :
// GPD SE AC 4.2.3 B and 4.2.3 D (All Device Applications)
rule.application === Ci.nsIAccessRulesManager.ALLOW_ALL;
if (!appMatched) {
return false; // bail out early.
}
// SE Applet
appletMatched = Array.isArray(rule.applet) ?
// GPD SE AC 4.2.3 A and 4.2.3 B (AID rule)
SEUtils.arraysEqual(rule.applet, this.aid) :
// GPD SE AC 4.2.3 C and 4.2.3 D (All AID)
rule.applet === Ci.nsIAccessRulesManager.ALL_APPLET;
return appletMatched;
},
_appCertHashMatches: function _appCertHashMatches(hashArray) {
if (!Array.isArray(hashArray)) {
return false;
}
return !!(hashArray.find((hash) => {
return SEUtils.arraysEqual(hash, this.certHash);
}));
}
};
function ACEService() {
this._rulesManagers = new Map();
this._rulesManagers.set(
SE.TYPE_UICC,
Cc["@mozilla.org/secureelement/access-control/rules-manager;1"]
.createInstance(Ci.nsIAccessRulesManager));
}
ACEService.prototype = {
_rulesManagers: null,
isAccessAllowed: function isAccessAllowed(localId, seType, aid) {
if(!Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps")) {
debug("Certified apps debug enabled, allowing access");
return Promise.resolve(true);
}
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
_getDevCertHashForApp: function getDevCertHashForApp(manifestURL) {
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
classID: Components.ID("{882a7463-2ca7-4d61-a89a-10eb6fd70478}"),
contractID: "@mozilla.org/secureelement/access-control/ace;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessControlEnforcer])
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ACEService]);

Просмотреть файл

@ -1,2 +0,0 @@
component {882a7463-2ca7-4d61-a89a-10eb6fd70478} ACEService.js
contract @mozilla.org/secureelement/access-control/ace;1 {882a7463-2ca7-4d61-a89a-10eb6fd70478}

Просмотреть файл

@ -1,436 +0,0 @@
/* 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/. */
/* Copyright © 2015, Deutsche Telekom, Inc. */
"use strict";
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/systemlibs.js");
XPCOMUtils.defineLazyServiceGetter(this, "UiccConnector",
"@mozilla.org/secureelement/connector/uicc;1",
"nsISecureElementConnector");
XPCOMUtils.defineLazyModuleGetter(this, "SEUtils",
"resource://gre/modules/SEUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "SE", function() {
let obj = {};
Cu.import("resource://gre/modules/se_consts.js", obj);
return obj;
});
XPCOMUtils.defineLazyGetter(this, "GP", function() {
let obj = {};
Cu.import("resource://gre/modules/gp_consts.js", obj);
return obj;
});
var DEBUG = SE.DEBUG_ACE;
function debug(msg) {
if (DEBUG) {
dump("-*- GPAccessRulesManager " + msg);
}
}
/**
* Based on [1] - "GlobalPlatform Device Technology
* Secure Element Access Control Version 1.0".
* GPAccessRulesManager reads and parses access rules from SE file system
* as defined in section #7 of [1]: "Structure of Access Rule Files (ARF)".
* Rules retrieval from ARA-M applet is not implmented due to lack of
* commercial implemenations of ARA-M.
* @todo Bug 1137537: Implement ARA-M support according to section #4 of [1]
*/
function GPAccessRulesManager() {}
GPAccessRulesManager.prototype = {
// source [1] section 7.1.3 PKCS#15 Selection
PKCS_AID: "a000000063504b43532d3135",
// APDUs (ISO 7816-4) for accessing rules on SE file system
// see for more details: http://www.cardwerk.com/smartcards/
// smartcard_standard_ISO7816-4_6_basic_interindustry_commands.aspx
READ_BINARY: [GP.CLA_SM, GP.INS_RB, GP.P1_RB, GP.P2_RB],
GET_RESPONSE: [GP.CLA_SM, GP.INS_GR, GP.P1_GR, GP.P2_GR],
SELECT_BY_DF: [GP.CLA_SM, GP.INS_SF, GP.P1_SF_DF, GP.P2_SF_FCP],
// Non-null if there is a channel open
channel: null,
// Refresh tag path in the acMain file as described in GPD spec,
// sections 7.1.5 and C.1.
REFRESH_TAG_PATH: [GP.TAG_SEQUENCE, GP.TAG_OCTETSTRING],
refreshTag: null,
// Contains rules as read from the SE
rules: [],
// Returns the latest rules. Results are cached.
getAccessRules: function getAccessRules() {
debug("getAccessRules");
return new Promise((resolve, reject) => {
this._readAccessRules(() => resolve(this.rules));
});
},
_readAccessRules: Task.async(function*(done) {
try {
yield this._openChannel(this.PKCS_AID);
let odf = yield this._readODF();
let dodf = yield this._readDODF(odf);
let acmf = yield this._readACMF(dodf);
let refreshTag = acmf[this.REFRESH_TAG_PATH[0]]
[this.REFRESH_TAG_PATH[1]];
// Update cached rules based on refreshTag.
if (SEUtils.arraysEqual(this.refreshTag, refreshTag)) {
debug("_readAccessRules: refresh tag equals to the one saved.");
yield this._closeChannel();
return done();
}
this.refreshTag = refreshTag;
debug("_readAccessRules: refresh tag saved: " + this.refreshTag);
let acrf = yield this._readACRules(acmf);
let accf = yield this._readACConditions(acrf);
this.rules = yield this._parseRules(acrf, accf);
DEBUG && debug("_readAccessRules: " + JSON.stringify(this.rules, 0, 2));
yield this._closeChannel();
done();
} catch (error) {
debug("_readAccessRules: " + error);
this.rules = [];
yield this._closeChannel();
done();
}
}),
_openChannel: function _openChannel(aid) {
if (this.channel !== null) {
debug("_openChannel: Channel already opened, rejecting.");
return Promise.reject();
}
return new Promise((resolve, reject) => {
UiccConnector.openChannel(aid, {
notifyOpenChannelSuccess: (channel, openResponse) => {
debug("_openChannel/notifyOpenChannelSuccess: Channel " + channel +
" opened, open response: " + openResponse);
this.channel = channel;
resolve();
},
notifyError: (error) => {
debug("_openChannel/notifyError: failed to open channel, error: " +
error);
reject(error);
}
});
});
},
_closeChannel: function _closeChannel() {
if (this.channel === null) {
debug("_closeChannel: Channel not opened, rejecting.");
return Promise.reject();
}
return new Promise((resolve, reject) => {
UiccConnector.closeChannel(this.channel, {
notifyCloseChannelSuccess: () => {
debug("_closeChannel/notifyCloseChannelSuccess: chanel " +
this.channel + " closed");
this.channel = null;
resolve();
},
notifyError: (error) => {
debug("_closeChannel/notifyError: error closing channel, error" +
error);
reject(error);
}
});
});
},
_exchangeAPDU: function _exchangeAPDU(bytes) {
DEBUG && debug("apdu " + JSON.stringify(bytes));
let apdu = this._bytesToAPDU(bytes);
return new Promise((resolve, reject) => {
UiccConnector.exchangeAPDU(this.channel, apdu.cla,
apdu.ins, apdu.p1, apdu.p2, apdu.data, apdu.le,
{
notifyExchangeAPDUResponse: (sw1, sw2, data) => {
debug("APDU response is " + sw1.toString(16) + sw2.toString(16) +
" data: " + data);
// 90 00 is "success"
if (sw1 !== 0x90 && sw2 !== 0x00) {
debug("rejecting APDU response");
reject(new Error("Response " + sw1 + "," + sw2));
return;
}
resolve(this._parseTLV(data));
},
notifyError: (error) => {
debug("_exchangeAPDU/notifyError " + error);
reject(error);
}
}
);
});
},
_readBinaryFile: function _readBinaryFile(selectResponse) {
DEBUG && debug("Select response: " + JSON.stringify(selectResponse));
// 0x80 tag parameter - get the elementary file (EF) length
// without structural information.
let fileLength = selectResponse[GP.TAG_FCP][0x80];
// If file is empty, no need to attempt to read it.
if (fileLength[0] === 0 && fileLength[1] === 0) {
return Promise.resolve(null);
}
// TODO READ BINARY with filelength not supported
// let readApdu = this.READ_BINARY.concat(fileLength);
return this._exchangeAPDU(this.READ_BINARY);
},
_selectAndRead: function _selectAndRead(df) {
return this._exchangeAPDU(this.SELECT_BY_DF.concat(df.length & 0xFF, df))
.then((resp) => this._readBinaryFile(resp));
},
_readODF: function _readODF() {
debug("_readODF");
return this._selectAndRead(GP.ODF_DF);
},
_readDODF: function _readDODF(odfFile) {
debug("_readDODF, ODF file: " + odfFile);
// Data Object Directory File (DODF) is used as an entry point to the
// Access Control data. It is specified in PKCS#15 section 6.7.6.
// DODF is referenced by the ODF file, which looks as follows:
// A7 06
// 30 04
// 04 02 XY WZ
// where [0xXY, 0xWZ] is a DF of DODF file.
let DODF_DF = odfFile[GP.TAG_EF_ODF][GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING];
return this._selectAndRead(DODF_DF);
},
_readACMF: function _readACMF(dodfFile) {
debug("_readACMF, DODF file: " + dodfFile);
// ACMF file DF is referenced in DODF file, which looks like this:
//
// A1 29
// 30 00
// 30 0F
// 0C 0D 47 50 20 53 45 20 41 63 63 20 43 74 6C
// A1 14
// 30 12
// 06 0A 2A 86 48 86 FC 6B 81 48 01 01 <-- GPD registered OID
// 30 04
// 04 02 AB CD <-- ACMF DF
// A1 2B
// 30 00
// 30 0F
// 0C 0D 53 41 54 53 41 20 47 54 4F 20 31 2E 31
// A1 16
// 30 14
// 06 0C 2B 06 01 04 01 2A 02 6E 03 01 01 01 <-- some other OID
// 30 04
// 04 02 XY WZ <-- some other file's DF
//
// DODF file consists of DataTypes with oidDO entries. Entry with OID
// equal to "1.2.840.114283.200.1.1" ("2A 86 48 86 FC 6B 81 48 01 01")
// contains DF of the ACMF. In the file above, it means that ACMF DF
// equals to [0xAB, 0xCD], and not [0xXY, 0xWZ].
//
// Algorithm used to encode OID to an byte array:
// http://www.snmpsharpnet.com/?p=153
let gpdOid = [0x2A, // 1.2
0x86, 0x48, // 840
0x86, 0xFC, 0x6B, // 114283
0x81, 0x48, // 129
0x01, // 1
0x01]; // 1
let records = SEUtils.ensureIsArray(dodfFile[GP.TAG_EXTERNALDO]);
// Look for the OID registered for GPD SE.
let gpdRecords = records.filter((record) => {
let oid = record[GP.TAG_EXTERNALDO][GP.TAG_SEQUENCE][GP.TAG_OID];
return SEUtils.arraysEqual(oid, gpdOid);
});
// [1] 7.1.5: "There shall be only one ACMF file per Secure Element.
// If a Secure Element contains several ACMF files, then the security shall
// be considered compromised and the Access Control enforcer shall forbid
// access to all (...) apps."
if (gpdRecords.length !== 1) {
return Promise.reject(new Error(gpdRecords.length + " ACMF files found"));
}
let ACMain_DF = gpdRecords[0][GP.TAG_EXTERNALDO][GP.TAG_SEQUENCE]
[GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING];
return this._selectAndRead(ACMain_DF);
},
_readACRules: function _readACRules(acMainFile) {
debug("_readACRules, ACMain file: " + acMainFile);
// ACMF looks like this:
//
// 30 10
// 04 08 XX XX XX XX XX XX XX XX
// 30 04
// 04 02 XY WZ
//
// where [XY, WZ] is a DF of ACRF, and XX XX XX XX XX XX XX XX is a refresh
// tag.
let ACRules_DF = acMainFile[GP.TAG_SEQUENCE][GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING];
return this._selectAndRead(ACRules_DF);
},
_readACConditions: function _readACConditions(acRulesFile) {
debug("_readACCondition, ACRules file: " + acRulesFile);
let acRules = SEUtils.ensureIsArray(acRulesFile[GP.TAG_SEQUENCE]);
if (acRules.length === 0) {
debug("No rules found in ACRules file.");
return Promise.reject(new Error("No rules found in ACRules file"));
}
// We first read all the condition files referenced in the ACRules file,
// because ACRules file might reference one ACCondition file more than
// once. Since reading it isn't exactly fast, we optimize here.
let acReadQueue = Promise.resolve({});
acRules.forEach((ruleEntry) => {
let df = ruleEntry[GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING];
// Promise chain read condition entries:
let readAcCondition = (acConditionFiles) => {
if (acConditionFiles[df] !== undefined) {
debug("Skipping previously read acCondition df: " + df);
return acConditionFiles;
}
return this._selectAndRead(df)
.then((acConditionFileContents) => {
acConditionFiles[df] = acConditionFileContents;
return acConditionFiles;
});
}
acReadQueue = acReadQueue.then(readAcCondition);
});
return acReadQueue;
},
_parseRules: function _parseRules(acRulesFile, acConditionFiles) {
DEBUG && debug("_parseRules: acConditionFiles " + JSON.stringify(acConditionFiles));
let rules = [];
let acRules = SEUtils.ensureIsArray(acRulesFile[GP.TAG_SEQUENCE]);
acRules.forEach((ruleEntry) => {
DEBUG && debug("Parsing one rule: " + JSON.stringify(ruleEntry));
let rule = {};
// 0xA0 and 0x82 tags as per GPD spec sections C.1 - C.3. 0xA0 means
// that rule describes access to one SE applet only (and its AID is
// given). 0x82 means that rule describes acccess to all SE applets.
let oneApplet = ruleEntry[GP.TAG_GPD_AID];
let allApplets = ruleEntry[GP.TAG_GPD_ALL];
if (oneApplet) {
rule.applet = oneApplet[GP.TAG_OCTETSTRING];
} else if (allApplets) {
rule.applet = Ci.nsIAccessRulesManager.ALL_APPLET;
} else {
throw Error("Unknown applet definition");
}
let df = ruleEntry[GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING];
let condition = acConditionFiles[df];
if (condition === null) {
rule.application = Ci.nsIAccessRulesManager.DENY_ALL;
} else if (condition[GP.TAG_SEQUENCE]) {
if (!Array.isArray(condition[GP.TAG_SEQUENCE]) &&
!condition[GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]) {
rule.application = Ci.nsIAccessRulesManager.ALLOW_ALL;
} else {
rule.application = SEUtils.ensureIsArray(condition[GP.TAG_SEQUENCE])
.map((conditionEntry) => {
return conditionEntry[GP.TAG_OCTETSTRING];
});
}
} else {
throw Error("Unknown application definition");
}
DEBUG && debug("Rule parsed, adding to the list: " + JSON.stringify(rule));
rules.push(rule);
});
DEBUG && debug("All rules parsed, we have those in total: " + JSON.stringify(rules));
return rules;
},
_parseTLV: function _parseTLV(bytes) {
let containerTags = [
GP.TAG_SEQUENCE,
GP.TAG_FCP,
GP.TAG_GPD_AID,
GP.TAG_EXTERNALDO,
GP.TAG_INDIRECT,
GP.TAG_EF_ODF
];
return SEUtils.parseTLV(bytes, containerTags);
},
// TODO consider removing if better format for storing
// APDU consts will be introduced
_bytesToAPDU: function _bytesToAPDU(arr) {
let apdu = {
cla: arr[0] & 0xFF,
ins: arr[1] & 0xFF,
p1: arr[2] & 0xFF,
p2: arr[3] & 0xFF,
p3: arr[4] & 0xFF,
le: 0
};
let data = (apdu.p3 > 0) ? (arr.slice(5)) : [];
apdu.data = (data.length) ? SEUtils.byteArrayToHexString(data) : null;
return apdu;
},
classID: Components.ID("{3e046b4b-9e66-439a-97e0-98a69f39f55f}"),
contractID: "@mozilla.org/secureelement/access-control/rules-manager;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessRulesManager])
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([GPAccessRulesManager]);

Просмотреть файл

@ -1,2 +0,0 @@
component {3e046b4b-9e66-439a-97e0-98a69f39f55f} GPAccessRulesManager.js
contract @mozilla.org/secureelement/access-control/rules-manager;1 {3e046b4b-9e66-439a-97e0-98a69f39f55f}

Просмотреть файл

@ -1,508 +0,0 @@
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
*
* 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.
*/
/* Copyright © 2014, Deutsche Telekom, Inc. */
"use strict";
/* globals dump, Components, XPCOMUtils, SE, Services, UiccConnector,
SEUtils, ppmm, gMap, UUIDGenerator */
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/systemlibs.js");
XPCOMUtils.defineLazyGetter(this, "SE", () => {
let obj = {};
Cu.import("resource://gre/modules/se_consts.js", obj);
return obj;
});
// set to true in se_consts.js to see debug messages
var DEBUG = SE.DEBUG_SE;
function debug(s) {
if (DEBUG) {
dump("-*- SecureElement: " + s + "\n");
}
}
const SE_IPC_SECUREELEMENT_MSG_NAMES = [
"SE:GetSEReaders",
"SE:OpenChannel",
"SE:CloseChannel",
"SE:TransmitAPDU"
];
const SECUREELEMENTMANAGER_CONTRACTID =
"@mozilla.org/secureelement/parent-manager;1";
const SECUREELEMENTMANAGER_CID =
Components.ID("{48f4e650-28d2-11e4-8c21-0800200c9a66}");
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageBroadcaster");
XPCOMUtils.defineLazyServiceGetter(this, "UUIDGenerator",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
XPCOMUtils.defineLazyModuleGetter(this, "SEUtils",
"resource://gre/modules/SEUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "UiccConnector", () => {
let uiccClass = Cc["@mozilla.org/secureelement/connector/uicc;1"];
return uiccClass ? uiccClass.getService(Ci.nsISecureElementConnector) : null;
});
function getConnector(type) {
switch (type) {
case SE.TYPE_UICC:
return UiccConnector;
case SE.TYPE_ESE:
default:
debug("Unsupported SEConnector : " + type);
return null;
}
}
/**
* 'gMap' is a nested dictionary object that manages all the information
* pertaining to channels for a given application (appId). It manages the
* relationship between given application and its opened channels.
*/
XPCOMUtils.defineLazyGetter(this, "gMap", function() {
return {
// example structure of AppInfoMap
// {
// "appId1": {
// target: target1,
// channels: {
// "channelToken1": {
// seType: "uicc",
// aid: "aid1",
// channelNumber: 1
// },
// "channelToken2": { ... }
// }
// },
// "appId2": { ... }
// }
appInfoMap: {},
registerSecureElementTarget: function(appId, target) {
if (this.isAppIdRegistered(appId)) {
debug("AppId: " + appId + "already registered");
return;
}
this.appInfoMap[appId] = {
target: target,
channels: {}
};
debug("Registered a new SE target " + appId);
},
unregisterSecureElementTarget: function(target) {
let appId = Object.keys(this.appInfoMap).find((id) => {
return this.appInfoMap[id].target === target;
});
if (!appId) {
return;
}
debug("Unregistered SE Target for AppId: " + appId);
delete this.appInfoMap[appId];
},
isAppIdRegistered: function(appId) {
return this.appInfoMap[appId] !== undefined;
},
getChannelCountByAppIdType: function(appId, type) {
return Object.keys(this.appInfoMap[appId].channels)
.reduce((cnt, ch) => ch.type === type ? ++cnt : cnt, 0);
},
// Add channel to the appId. Upon successfully adding the entry
// this function will return the 'token'
addChannel: function(appId, type, aid, channelNumber) {
let token = UUIDGenerator.generateUUID().toString();
this.appInfoMap[appId].channels[token] = {
seType: type,
aid: aid,
channelNumber: channelNumber
};
return token;
},
removeChannel: function(appId, channelToken) {
if (this.appInfoMap[appId].channels[channelToken]) {
debug("Deleting channel with token : " + channelToken);
delete this.appInfoMap[appId].channels[channelToken];
}
},
getChannel: function(appId, channelToken) {
if (!this.appInfoMap[appId].channels[channelToken]) {
return null;
}
return this.appInfoMap[appId].channels[channelToken];
},
getChannelsByTarget: function(target) {
let appId = Object.keys(this.appInfoMap).find((id) => {
return this.appInfoMap[id].target === target;
});
if (!appId) {
return [];
}
return Object.keys(this.appInfoMap[appId].channels)
.map(token => this.appInfoMap[appId].channels[token]);
},
getTargets: function() {
return Object.keys(this.appInfoMap)
.map(appId => this.appInfoMap[appId].target);
},
};
});
/**
* 'SecureElementManager' is the main object that handles IPC messages from
* child process. It interacts with other objects such as 'gMap' & 'Connector
* instances (UiccConnector, eSEConnector)' to perform various
* SE-related (open, close, transmit) operations.
* @TODO: Bug 1118097 Support slot based SE/reader names
* @TODO: Bug 1118101 Introduce SE type specific permissions
*/
function SecureElementManager() {
this._registerMessageListeners();
this._registerSEListeners();
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
this._acEnforcer =
Cc["@mozilla.org/secureelement/access-control/ace;1"]
.getService(Ci.nsIAccessControlEnforcer);
}
SecureElementManager.prototype = {
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIMessageListener,
Ci.nsISEListener,
Ci.nsIObserver]),
classID: SECUREELEMENTMANAGER_CID,
classInfo: XPCOMUtils.generateCI({
classID: SECUREELEMENTMANAGER_CID,
classDescription: "SecureElementManager",
interfaces: [Ci.nsIMessageListener,
Ci.nsISEListener,
Ci.nsIObserver]
}),
// Stores information about supported SE types and their presence.
// key: secure element type, value: (Boolean) is present/accessible
_sePresence: {},
_acEnforcer: null,
_shutdown: function() {
this._acEnforcer = null;
this.secureelement = null;
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
this._unregisterMessageListeners();
this._unregisterSEListeners();
},
_registerMessageListeners: function() {
ppmm.addMessageListener("child-process-shutdown", this);
for (let msgname of SE_IPC_SECUREELEMENT_MSG_NAMES) {
ppmm.addMessageListener(msgname, this);
}
},
_unregisterMessageListeners: function() {
ppmm.removeMessageListener("child-process-shutdown", this);
for (let msgname of SE_IPC_SECUREELEMENT_MSG_NAMES) {
ppmm.removeMessageListener(msgname, this);
}
ppmm = null;
},
_registerSEListeners: function() {
let connector = getConnector(SE.TYPE_UICC);
if (!connector) {
return;
}
this._sePresence[SE.TYPE_UICC] = false;
connector.registerListener(this);
},
_unregisterSEListeners: function() {
Object.keys(this._sePresence).forEach((type) => {
let connector = getConnector(type);
if (connector) {
connector.unregisterListener(this);
}
});
this._sePresence = {};
},
notifySEPresenceChanged: function(type, isPresent) {
// we need to notify all targets, even those without open channels,
// app could've stored the reader without actually using it
debug("notifying DOM about SE state change");
this._sePresence[type] = isPresent;
gMap.getTargets().forEach(target => {
let result = { type: type, isPresent: isPresent };
target.sendAsyncMessage("SE:ReaderPresenceChanged", { result: result });
});
},
_canOpenChannel: function(appId, type) {
let opened = gMap.getChannelCountByAppIdType(appId, type);
let limit = SE.MAX_CHANNELS_ALLOWED_PER_SESSION;
// UICC basic channel is not accessible see comment in se_consts.js
limit = type === SE.TYPE_UICC ? limit - 1 : limit;
return opened < limit;
},
_handleOpenChannel: function(msg, callback) {
if (!this._canOpenChannel(msg.appId, msg.type)) {
debug("Max channels per session exceed");
callback({ error: SE.ERROR_GENERIC });
return;
}
let connector = getConnector(msg.type);
if (!connector) {
debug("No SE connector available");
callback({ error: SE.ERROR_NOTPRESENT });
return;
}
this._acEnforcer.isAccessAllowed(msg.appId, msg.type, msg.aid)
.then((allowed) => {
if (!allowed) {
callback({ error: SE.ERROR_SECURITY });
return;
}
connector.openChannel(SEUtils.byteArrayToHexString(msg.aid), {
notifyOpenChannelSuccess: (channelNumber, openResponse) => {
// Add the new 'channel' to the map upon success
let channelToken =
gMap.addChannel(msg.appId, msg.type, msg.aid, channelNumber);
if (channelToken) {
callback({
error: SE.ERROR_NONE,
channelToken: channelToken,
isBasicChannel: (channelNumber === SE.BASIC_CHANNEL),
openResponse: SEUtils.hexStringToByteArray(openResponse)
});
} else {
callback({ error: SE.ERROR_GENERIC });
}
},
notifyError: (reason) => {
debug("Failed to open the channel to AID : " +
SEUtils.byteArrayToHexString(msg.aid) +
", Rejected with Reason : " + reason);
callback({ error: SE.ERROR_GENERIC, reason: reason, response: [] });
}
});
})
.catch((error) => {
debug("Failed to get info from accessControlEnforcer " + error);
callback({ error: SE.ERROR_SECURITY });
});
},
_handleTransmit: function(msg, callback) {
let channel = gMap.getChannel(msg.appId, msg.channelToken);
if (!channel) {
debug("Invalid token:" + msg.channelToken + ", appId: " + msg.appId);
callback({ error: SE.ERROR_GENERIC });
return;
}
let connector = getConnector(channel.seType);
if (!connector) {
debug("No SE connector available");
callback({ error: SE.ERROR_NOTPRESENT });
return;
}
// Bug 1137533 - ACE GPAccessRulesManager APDU filters
connector.exchangeAPDU(channel.channelNumber, msg.apdu.cla, msg.apdu.ins,
msg.apdu.p1, msg.apdu.p2,
SEUtils.byteArrayToHexString(msg.apdu.data),
msg.apdu.le, {
notifyExchangeAPDUResponse: (sw1, sw2, response) => {
callback({
error: SE.ERROR_NONE,
sw1: sw1,
sw2: sw2,
response: SEUtils.hexStringToByteArray(response)
});
},
notifyError: (reason) => {
debug("Transmit failed, rejected with Reason : " + reason);
callback({ error: SE.ERROR_INVALIDAPPLICATION, reason: reason });
}
});
},
_handleCloseChannel: function(msg, callback) {
let channel = gMap.getChannel(msg.appId, msg.channelToken);
if (!channel) {
debug("Invalid token:" + msg.channelToken + ", appId:" + msg.appId);
callback({ error: SE.ERROR_GENERIC });
return;
}
let connector = getConnector(channel.seType);
if (!connector) {
debug("No SE connector available");
callback({ error: SE.ERROR_NOTPRESENT });
return;
}
connector.closeChannel(channel.channelNumber, {
notifyCloseChannelSuccess: () => {
gMap.removeChannel(msg.appId, msg.channelToken);
callback({ error: SE.ERROR_NONE });
},
notifyError: (reason) => {
debug("Failed to close channel with token: " + msg.channelToken +
", reason: "+ reason);
callback({ error: SE.ERROR_BADSTATE, reason: reason });
}
});
},
_handleGetSEReadersRequest: function(msg, target, callback) {
gMap.registerSecureElementTarget(msg.appId, target);
let readers = Object.keys(this._sePresence).map(type => {
return { type: type, isPresent: this._sePresence[type] };
});
callback({ readers: readers, error: SE.ERROR_NONE });
},
_handleChildProcessShutdown: function(target) {
let channels = gMap.getChannelsByTarget(target);
let createCb = (seType, channelNumber) => {
return {
notifyCloseChannelSuccess: () => {
debug("closed " + seType + ", channel " + channelNumber);
},
notifyError: (reason) => {
debug("Failed to close " + seType + " channel " +
channelNumber + ", reason: " + reason);
}
};
};
channels.forEach((channel) => {
let connector = getConnector(channel.seType);
if (!connector) {
return;
}
connector.closeChannel(channel.channelNumber,
createCb(channel.seType, channel.channelNumber));
});
gMap.unregisterSecureElementTarget(target);
},
_sendSEResponse: function(msg, result) {
let promiseStatus = (result.error === SE.ERROR_NONE) ? "Resolved" : "Rejected";
result.resolverId = msg.data.resolverId;
msg.target.sendAsyncMessage(msg.name + promiseStatus, {result: result});
},
_isValidMessage: function(msg) {
let appIdValid = gMap.isAppIdRegistered(msg.data.appId);
return msg.name === "SE:GetSEReaders" ? true : appIdValid;
},
/**
* nsIMessageListener interface methods.
*/
receiveMessage: function(msg) {
DEBUG && debug("Received '" + msg.name + "' message from content process" +
": " + JSON.stringify(msg.data));
if (msg.name === "child-process-shutdown") {
this._handleChildProcessShutdown(msg.target);
return null;
}
if (SE_IPC_SECUREELEMENT_MSG_NAMES.indexOf(msg.name) === -1) {
debug("Ignoring unknown message type: " + msg.name);
return null;
}
let callback = (result) => this._sendSEResponse(msg, result);
if (!this._isValidMessage(msg)) {
debug("Message not valid");
callback({ error: SE.ERROR_GENERIC });
return null;
}
switch (msg.name) {
case "SE:GetSEReaders":
this._handleGetSEReadersRequest(msg.data, msg.target, callback);
break;
case "SE:OpenChannel":
this._handleOpenChannel(msg.data, callback);
break;
case "SE:CloseChannel":
this._handleCloseChannel(msg.data, callback);
break;
case "SE:TransmitAPDU":
this._handleTransmit(msg.data, callback);
break;
}
return null;
},
/**
* nsIObserver interface methods.
*/
observe: function(subject, topic, data) {
if (topic === NS_XPCOM_SHUTDOWN_OBSERVER_ID) {
this._shutdown();
}
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SecureElementManager]);

Просмотреть файл

@ -1,18 +0,0 @@
# Copyright 2012 Mozilla Foundation and Mozilla contributors
#
# 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.
# SecureElementManager
component {48f4e650-28d2-11e4-8c21-0800200c9a66} SecureElement.js
contract @mozilla.org/secureelement/parent-manager;1 {48f4e650-28d2-11e4-8c21-0800200c9a66}
category profile-after-change SecureElementManager @mozilla.org/secureelement/parent-manager;1

Просмотреть файл

@ -1,360 +0,0 @@
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
*
* 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.
*/
/* Copyright © 2014, Deutsche Telekom, Inc. */
"use strict";
/* globals Components, XPCOMUtils, SE, dump, libcutils, Services,
iccService, SEUtils */
const { interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/systemlibs.js");
XPCOMUtils.defineLazyGetter(this, "SE", function() {
let obj = {};
Cu.import("resource://gre/modules/se_consts.js", obj);
return obj;
});
// set to true in se_consts.js to see debug messages
var DEBUG = SE.DEBUG_CONNECTOR;
function debug(s) {
if (DEBUG) {
dump("-*- UiccConnector: " + s + "\n");
}
}
XPCOMUtils.defineLazyModuleGetter(this, "SEUtils",
"resource://gre/modules/SEUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "iccService",
"@mozilla.org/icc/iccservice;1",
"nsIIccService");
const UICCCONNECTOR_CONTRACTID =
"@mozilla.org/secureelement/connector/uicc;1";
const UICCCONNECTOR_CID =
Components.ID("{8e040e5d-c8c3-4c1b-ac82-c00d25d8c4a4}");
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
// TODO: Bug 1118099 - Add multi-sim support.
// In the Multi-sim, there is more than one client.
// For now, use default clientID as 0. Ideally, SE parent process would like to
// know which clients (uicc slot) are connected to CLF over SWP interface.
const PREFERRED_UICC_CLIENTID =
libcutils.property_get("ro.moz.se.def_client_id", "0");
/**
* 'UiccConnector' object is a wrapper over iccService's channel management
* related interfaces that implements nsISecureElementConnector interface.
*/
function UiccConnector() {
this._init();
}
UiccConnector.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsISecureElementConnector,
Ci.nsIIccListener]),
classID: UICCCONNECTOR_CID,
classInfo: XPCOMUtils.generateCI({
classID: UICCCONNECTOR_CID,
contractID: UICCCONNECTOR_CONTRACTID,
classDescription: "UiccConnector",
interfaces: [Ci.nsISecureElementConnector,
Ci.nsIIccListener,
Ci.nsIObserver]
}),
_SEListeners: [],
_isPresent: false,
_init: function() {
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID);
icc.registerListener(this);
// Update the state in order to avoid race condition.
// By this time, 'notifyCardStateChanged (with proper card state)'
// may have occurred already before this module initialization.
this._updatePresenceState();
},
_shutdown: function() {
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID);
icc.unregisterListener(this);
},
_updatePresenceState: function() {
let uiccNotReadyStates = [
Ci.nsIIcc.CARD_STATE_UNKNOWN,
Ci.nsIIcc.CARD_STATE_ILLEGAL,
Ci.nsIIcc.CARD_STATE_PERSONALIZATION_IN_PROGRESS,
Ci.nsIIcc.CARD_STATE_PERMANENT_BLOCKED,
Ci.nsIIcc.CARD_STATE_UNDETECTED
];
let cardState = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID).cardState;
let uiccPresent = cardState !== null &&
uiccNotReadyStates.indexOf(cardState) == -1;
if (this._isPresent === uiccPresent) {
return;
}
debug("Uicc presence changed " + this._isPresent + " -> " + uiccPresent);
this._isPresent = uiccPresent;
this._SEListeners.forEach((listener) => {
listener.notifySEPresenceChanged(SE.TYPE_UICC, this._isPresent);
});
},
// See GP Spec, 11.1.4 Class Byte Coding
_setChannelToCLAByte: function(cla, channel) {
if (channel < SE.LOGICAL_CHANNEL_NUMBER_LIMIT) {
// b7 = 0 indicates the first interindustry class byte coding
cla = (cla & 0x9C) & 0xFF | channel;
} else if (channel < SE.SUPPLEMENTARY_LOGICAL_CHANNEL_NUMBER_LIMIT) {
// b7 = 1 indicates the further interindustry class byte coding
cla = (cla & 0xB0) & 0xFF | 0x40 | (channel - SE.LOGICAL_CHANNEL_NUMBER_LIMIT);
} else {
debug("Channel number must be within [0..19]");
return SE.ERROR_GENERIC;
}
return cla;
},
_doGetOpenResponse: function(channel, length, callback) {
// Le value is set. It means that this is a request for all available
// response bytes.
let cla = this._setChannelToCLAByte(SE.CLA_GET_RESPONSE, channel);
this.exchangeAPDU(channel, cla, SE.INS_GET_RESPONSE, 0x00, 0x00,
null, length, {
notifyExchangeAPDUResponse: function(sw1, sw2, response) {
debug("GET Response : " + response);
if (callback) {
callback({
error: SE.ERROR_NONE,
sw1: sw1,
sw2: sw2,
response: response
});
}
},
notifyError: function(reason) {
debug("Failed to get open response: " +
", Rejected with Reason : " + reason);
if (callback) {
callback({ error: SE.ERROR_INVALIDAPPLICATION, reason: reason });
}
}
});
},
_doIccExchangeAPDU: function(channel, cla, ins, p1, p2, p3,
data, appendResp, callback) {
let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID);
icc.iccExchangeAPDU(channel, cla & 0xFC, ins, p1, p2, p3, data, {
notifyExchangeAPDUResponse: (sw1, sw2, response) => {
debug("sw1 : " + sw1 + ", sw2 : " + sw2 + ", response : " + response);
// According to ETSI TS 102 221 , Section 7.2.2.3.1,
// Enforce 'Procedure bytes' checks before notifying the callback.
// Note that 'Procedure bytes'are special cases.
// There is no need to handle '0x60' procedure byte as it implies
// no-action from SE stack perspective. This procedure byte is not
// notified to application layer.
if (sw1 === 0x6C) {
// Use the previous command header with length as second procedure
// byte (SW2) as received and repeat the procedure.
// Recursive! and Pass empty response '' as args, since '0x6C'
// procedure does not have to deal with appended responses.
this._doIccExchangeAPDU(channel, cla, ins, p1, p2,
sw2, data, "", callback);
} else if (sw1 === 0x61) {
// Since the terminal waited for a second procedure byte and
// received it (sw2), send a GET RESPONSE command header to the UICC
// with a maximum length of 'XX', where 'XX' is the value of the
// second procedure byte (SW2).
let claWithChannel = this._setChannelToCLAByte(SE.CLA_GET_RESPONSE,
channel);
// Recursive, with GET RESPONSE bytes and '0x61' procedure IS interested
// in appended responses. Pass appended response and note that p3=sw2.
this._doIccExchangeAPDU(channel, claWithChannel, SE.INS_GET_RESPONSE,
0x00, 0x00, sw2, null,
(response ? response + appendResp : appendResp),
callback);
} else if (callback) {
callback.notifyExchangeAPDUResponse(sw1, sw2, response);
}
},
notifyError: (reason) => {
debug("Failed to trasmit C-APDU over the channel # : " + channel +
", Rejected with Reason : " + reason);
if (callback) {
callback.notifyError(reason);
}
}
});
},
/**
* nsISecureElementConnector interface methods.
*/
/**
* Opens a channel on a default clientId
*/
openChannel: function(aid, callback) {
if (!this._isPresent) {
callback.notifyError(SE.ERROR_NOTPRESENT);
return;
}
// TODO: Bug 1118106: Handle Resource management / leaks by persisting
// the newly opened channel in some persistent storage so that when this
// module gets restarted (say after opening a channel) in the event of
// some erroneous conditions such as gecko restart /, crash it can read
// the persistent storage to check if there are any held resources
// (opened channels) and close them.
let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID);
icc.iccOpenChannel(aid, {
notifyOpenChannelSuccess: (channel) => {
this._doGetOpenResponse(channel, 0x00, function(result) {
if (callback) {
callback.notifyOpenChannelSuccess(channel, result.response);
}
});
},
notifyError: (reason) => {
debug("Failed to open the channel to AID : " + aid +
", Rejected with Reason : " + reason);
if (callback) {
callback.notifyError(reason);
}
}
});
},
/**
* Transmit the C-APDU (command) on default clientId.
*/
exchangeAPDU: function(channel, cla, ins, p1, p2, data, le, callback) {
if (!this._isPresent) {
callback.notifyError(SE.ERROR_NOTPRESENT);
return;
}
if (data && data.length % 2 !== 0) {
callback.notifyError("Data should be a hex string with length % 2 === 0");
return;
}
cla = this._setChannelToCLAByte(cla, channel);
let lc = data ? data.length / 2 : 0;
let p3 = lc || le;
if (lc && (le !== -1)) {
data += SEUtils.byteArrayToHexString([le]);
}
// Pass empty response '' as args as we are not interested in appended
// responses yet!
debug("exchangeAPDU on Channel # " + channel);
this._doIccExchangeAPDU(channel, cla, ins, p1, p2, p3, data, "",
callback);
},
/**
* Closes the channel on default clientId.
*/
closeChannel: function(channel, callback) {
if (!this._isPresent) {
callback.notifyError(SE.ERROR_NOTPRESENT);
return;
}
let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID);
icc.iccCloseChannel(channel, {
notifyCloseChannelSuccess: function() {
debug("closeChannel successfully closed the channel # : " + channel);
if (callback) {
callback.notifyCloseChannelSuccess();
}
},
notifyError: function(reason) {
debug("Failed to close the channel # : " + channel +
", Rejected with Reason : " + reason);
if (callback) {
callback.notifyError(reason);
}
}
});
},
registerListener: function(listener) {
if (this._SEListeners.indexOf(listener) !== -1) {
throw Cr.NS_ERROR_UNEXPECTED;
}
this._SEListeners.push(listener);
// immediately notify listener about the current state
listener.notifySEPresenceChanged(SE.TYPE_UICC, this._isPresent);
},
unregisterListener: function(listener) {
let idx = this._SEListeners.indexOf(listener);
if (idx !== -1) {
this._SEListeners.splice(idx, 1);
}
},
/**
* nsIIccListener interface methods.
*/
notifyStkCommand: function() {},
notifyStkSessionEnd: function() {},
notifyIccInfoChanged: function() {},
notifyCardStateChanged: function() {
debug("Card state changed, updating UICC presence.");
this._updatePresenceState();
},
/**
* nsIObserver interface methods.
*/
observe: function(subject, topic, data) {
if (topic === NS_XPCOM_SHUTDOWN_OBSERVER_ID) {
this._shutdown();
}
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([UiccConnector]);

Просмотреть файл

@ -1,17 +0,0 @@
# Copyright 2012 Mozilla Foundation and Mozilla contributors
#
# 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.
# UiccConnector
component {8e040e5d-c8c3-4c1b-ac82-c00d25d8c4a4} UiccConnector.js
contract @mozilla.org/secureelement/connector/uicc;1 {8e040e5d-c8c3-4c1b-ac82-c00d25d8c4a4}

Просмотреть файл

@ -1,62 +0,0 @@
/* 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/. */
/* Copyright © 2015, Deutsche Telekom, Inc. */
/* Object Directory File (ODF) is an elementary file which contain
pointers to other EFs. It is specified in PKCS#15 section 6.7. */
this.ODF_DF = [0x50, 0x31];
/* ISO 7816-4: secure messaging */
this.CLA_SM = 0x00;
/* ISO 7816-4, 5.4.1 table 11 */
this.INS_SF = 0xA4; // select file
this.INS_GR = 0xC0; // get response
this.INS_RB = 0xB0; // read binary
/* ISO 7816-4: select file, see 6.11.3, table 58 & 59 */
this.P1_SF_DF = 0x00; // select DF
this.P2_SF_FCP = 0x04; // return FCP
/* ISO 7816-4: read binary, 6.1.3. P1 and P2 describe offset of the first byte
to be read. We always read the whole files at the moment. */
this.P1_RB = 0x00;
this.P2_RB = 0x00;
/* ISO 7816-4: get response, 7.1.3 table 74, P1-P2 '0000' (other values RFU) */
this.P1_GR = 0x00;
this.P2_GR = 0x00;
/* ISO 7816-4: 5.1.5 File Control Information, Table 1. For FCP and FMD. */
this.TAG_PROPRIETARY = 0x00;
this.TAG_NON_TLV = 0x53;
this.TAG_BER_TLV = 0x73;
/* ASN.1 tags */
this.TAG_SEQUENCE = 0x30;
this.TAG_OCTETSTRING = 0x04;
this.TAG_OID = 0x06; // Object Identifier
/* ISO 7816-4: 5.1.5 File Control Information, Templates. */
this.TAG_FCP = 0x62; // File control parameters template
this.TAG_FMD = 0x64; // File management data template
this.TAG_FCI = 0x6F; // File control information template
/* EF_DIR tags */
this.TAG_APPLTEMPLATE = 0x61;
this.TAG_APPLIDENTIFIER = 0x4F;
this.TAG_APPLLABEL = 0x50;
this.TAG_APPLPATH = 0x51;
this.TAG_GPD_ALL = 0x82; // EF-ACRules - GPD spec. "all applets"
/* Generic TLVs that are parsed */
this.TAG_GPD_AID = 0xA0; // AID in the EF-ACRules - GPD spec, "one applet"
this.TAG_EXTERNALDO = 0xA1; // External data objects - PKCS#15
this.TAG_INDIRECT = 0xA5; // Indirect value.
this.TAG_EF_ODF = 0xA7; // Elemenetary File Object Directory File
// Allow this file to be imported via Components.utils.import().
this.EXPORTED_SYMBOLS = Object.keys(this);

Просмотреть файл

@ -1,32 +0,0 @@
/* 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/. */
/* Copyright © 2015, Deutsche Telekom, Inc. */
#include "nsISupports.idl"
interface nsIVariant;
[scriptable, uuid(4994a960-26d9-4d71-82dd-4505bd97bf2a)]
interface nsIAccessControlEnforcer : nsISupports
{
/**
* Determines whether application identified by its ID should be allowed
* to access Secure Element's applet identified by its AID. Decision
* is made according to the GPD specification.
*
* @param localId
* ID of an application accessing SE
* @param seType
* Type of the SE.
* @param aid
* AID of a SE applet
* @return Promise which is resolved to true if access should be allowed,
* false otherwise, and rejected if the application contains
* no developer certificate.
*/
jsval isAccessAllowed(in unsigned long localId,
in DOMString seType,
in DOMString aid);
};

Просмотреть файл

@ -1,50 +0,0 @@
/* 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/. */
/* Copyright © 2015, Deutsche Telekom, Inc. */
#include "nsISupports.idl"
[scriptable, uuid(7baedd2a-3189-4b03-b2a3-34016043b5e2)]
interface nsIAccessRulesManager : nsISupports
{
/* Wildcard: rule allows all applications to access an SE applet */
const unsigned short ALLOW_ALL = 1;
/* Wildcard: rule denies all applications to access an SE applet */
const unsigned short DENY_ALL = 2;
/* Wildcard: rule allows application(s) access to all SE applets */
const unsigned short ALL_APPLET = 3;
/**
* Initiates Access Rules Manager, this should perform the initial
* reading of rules from access rule source
* @return Promise which is resolved if init is successful or rejected
* otherwise
*/
jsval init();
/**
* Retrieves all access rules.
*
* Rules are stored in an array. Each rule contains the following properties:
* - applet - describes an SE applet referenced by this rule. Might equal
* to an applet AID (as a byte array), or to a wildcard "all"
* meaning all applets.
* - application - describes an application referenced by this rule. Might
* be an array of developer certificate hashes (each as
* a byte array) in which case it lists all applications
* allowed access. Alternatively, might equal to wildcard
* "allowed-all" or "denied-all".
*
* Example rule format:
* [{ applet: ALL_APPLET,
* application: [[0x01, 0x02, ..., 0x20],
* [0x20, 0x19, ...., 0x01]],
* { applet: [0x00, 0x01, ..., 0x05],
* application: ALLOW_ALL}}]
*
* @return Promise which resolves with Array containing parsed access rules
*/
jsval getAccessRules();
};

Просмотреть файл

@ -1,124 +0,0 @@
/* 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/. */
#include "nsISupports.idl"
[scriptable, uuid(1ff3f35a-1b6f-4e65-a89e-a363b8604cd7)]
interface nsISEChannelCallback : nsISupports
{
/**
* Callback function to notify on successfully opening a logical channel.
*
* @param channel
* The Channel Number/Handle that is successfully opened.
* @param openResponse
* Response from SE for OpenChannel operation.
*/
void notifyOpenChannelSuccess(in long channel, in DOMString openResponse);
/**
* Callback function to notify on successfully closing the logical channel.
*
*/
void notifyCloseChannelSuccess();
/**
* Callback function to notify the status of 'seExchangeAPDU' command.
*
* @param sw1
* Response's First Status Byte
* @param sw2
* Response's Second Status Byte
* @param data
* Response's data
*/
void notifyExchangeAPDUResponse(in octet sw1,
in octet sw2,
in DOMString data);
/**
* Callback function to notify error
*
* @param error
* Error describing the reason for failure.
*/
void notifyError(in DOMString error);
};
[scriptable, uuid(417f59ee-f582-45b9-9a4e-e9dcefecb4f7)]
interface nsISEListener : nsISupports
{
void notifySEPresenceChanged(in DOMString seType, in boolean isPresent);
};
[scriptable, uuid(3cef313a-1d01-432d-9cd2-6610a80911f3)]
interface nsISecureElementConnector : nsISupports
{
/**
* Open a logical communication channel with the specific secure element type
*
* @param aid
* Application Identifier of the Card Applet on the secure element.
* @param callback
* callback to notify the result of the operation.
*/
void openChannel(in DOMString aid,
in nsISEChannelCallback callback);
/**
* Exchanges APDU channel with the specific secure element type
*
* @param channel
* Channel on which C-APDU to be transmitted.
* @param cla
Class Byte.
* @param ins
Instruction Byte
* @param p1
Reference parameter first byte
* @param p2
Reference parameter second byte
* Refer to 3G TS 31.101 , 10.2 'Command APDU Structure' for all the cases.
* @param data
Sequence of C-APDU data octets
* @param le [optional]
* le is the length of expected response. If the response is not expected,
it should be explicitly set to -1.
* @param callback
* callback to notify the result of the operation.
*/
void exchangeAPDU(in long channel,
in octet cla,
in octet ins,
in octet p1,
in octet p2,
in DOMString data,
in short le,
in nsISEChannelCallback callback);
/**
* Closes the logical communication channel to the specific secure element type
*
* @param channel
* Channel to be closed.
* @param callback
* callback to notify the result of the operation.
*/
void closeChannel(in long channel,
in nsISEChannelCallback callback);
/**
* Register a Secure Element listener
*
* @param listener
*/
void registerListener(in nsISEListener listener);
/**
* Unregister a Secure Element listener
*
* @param listener
*/
void unregisterListener(in nsISEListener listener);
};

Просмотреть файл

@ -1,68 +0,0 @@
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
*
* 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.
*/
/* Copyright © 2014, Deutsche Telekom, Inc. */
// Set to true to debug SecureElement (SE) stack
this.DEBUG_ALL = false;
// Set individually to debug specific layers
this.DEBUG_CONNECTOR = DEBUG_ALL || false;
this.DEBUG_ACE = DEBUG_ALL || false ;
this.DEBUG_SE = DEBUG_ALL || false ;
// Maximun logical channels per session.
// For 'uicc' SE type this value is 3, as opening a basic channel' : 0
// is not allowed for security reasons. In such scenarios, possible
// supplementary logical channels available are : [1, 2, or 3].
// However,Other SE types may support upto max 4 (including '0').
this.MAX_CHANNELS_ALLOWED_PER_SESSION = 4;
this.BASIC_CHANNEL = 0;
// According GPCardSpec 2.2
this.MAX_APDU_LEN = 255; // including APDU header
// CLA (1 byte) + INS (1 byte) + P1 (1 byte) + P2 (1 byte)
this.APDU_HEADER_LEN = 4;
this.LOGICAL_CHANNEL_NUMBER_LIMIT = 4;
this.SUPPLEMENTARY_LOGICAL_CHANNEL_NUMBER_LIMIT = 20;
this.MIN_AID_LEN = 5;
this.MAX_AID_LEN = 16;
this.CLA_GET_RESPONSE = 0x00;
this.INS_SELECT = 0xA4;
this.INS_MANAGE_CHANNEL = 0x70;
this.INS_GET_RESPONSE = 0xC0;
// Match the following errors with SecureElement.webidl's SEError enum values
this.ERROR_NONE = "";
this.ERROR_SECURITY = "SESecurityError";
this.ERROR_IO = "SEIoError";
this.ERROR_BADSTATE = "SEBadStateError";
this.ERROR_INVALIDCHANNEL = "SEInvalidChannelError";
this.ERROR_INVALIDAPPLICATION = "SEInvalidApplicationError";
this.ERROR_GENERIC = "SEGenericError";
this.ERROR_NOTPRESENT = "SENotPresentError";
this.ERROR_ILLEGALPARAMETER = "SEIllegalParameterError";
this.TYPE_UICC = "uicc";
this.TYPE_ESE = "eSE";
// Allow this file to be imported via Components.utils.import().
this.EXPORTED_SYMBOLS = Object.keys(this);

Просмотреть файл

@ -1,9 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Strips spaces, and returns a byte array.
*/
function formatHexAndCreateByteArray(hexStr) {
return SEUtils.hexStringToByteArray(hexStr.replace(/\s+/g, ""));
}

Просмотреть файл

@ -1,228 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/* globals run_next_test, add_test, ok, Components, SEUtils */
/* exported run_test */
Components.utils.import("resource://gre/modules/SEUtils.jsm");
var GP = {};
Components.utils.import("resource://gre/modules/gp_consts.js", GP);
const VALID_HEX_STR = "0123456789ABCDEF";
const VALID_BYTE_ARR = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF];
// This set should be what the actual ACE uses.
var containerTags = [
GP.TAG_SEQUENCE,
GP.TAG_FCP,
GP.TAG_GPD_AID,
GP.TAG_EXTERNALDO,
GP.TAG_INDIRECT,
GP.TAG_EF_ODF
];
function run_test() {
ok(!!SEUtils, "SEUtils should be available");
run_next_test();
}
add_test(function test_byteArrayToHexString() {
let hexStr = SEUtils.byteArrayToHexString(VALID_BYTE_ARR);
ok(hexStr === VALID_HEX_STR,
"should convert byte Array to uppercased hex string");
[[], null, undefined].forEach((input) => {
hexStr = SEUtils.byteArrayToHexString(input);
ok(hexStr === "", "invalid arg:" + input + " should return empty string");
});
run_next_test();
});
add_test(function test_hexStringToByteArray() {
let byteArr = SEUtils.hexStringToByteArray(VALID_HEX_STR);
ok(SEUtils.arraysEqual(byteArr, VALID_BYTE_ARR),
"should convert uppercased string to byte Array");
byteArr = SEUtils.hexStringToByteArray(VALID_HEX_STR.toLowerCase());
ok(SEUtils.arraysEqual(byteArr, VALID_BYTE_ARR),
"should convert lowercased string to byte Array");
["", null, undefined, "123"].forEach((input) => {
byteArr = SEUtils.hexStringToByteArray(input);
ok(Array.isArray(byteArr) && byteArr.length === 0,
"invalid arg: " + input + " should be empty Array");
});
run_next_test();
});
add_test(function test_arraysEqual() {
ok(SEUtils.arraysEqual([1, 2, 3], [1, 2, 3]),
"should return true on equal Arrays");
[[1], [1, 2, 4], [3, 2, 1]].forEach((input) => {
ok(!SEUtils.arraysEqual([1, 2, 3], input),
"should return false when Arrays not equal");
});
[null, undefined].forEach((input) => {
ok(!SEUtils.arraysEqual([1, 2, 3], input),
"should return false when comparing Array with invalid argument");
ok(!SEUtils.arraysEqual(input, input),
"should return false when both args are invalid");
});
run_next_test();
});
add_test(function test_ensureIsArray() {
let obj = {a: "a"};
let targetArray = [obj];
let result = null;
result = SEUtils.ensureIsArray(obj);
ok(targetArray[0].a === result[0].a,
"should return true if array element contains the same value");
deepEqual(result, targetArray,
"result should be deeply equal to targetArray");
result = SEUtils.ensureIsArray(targetArray);
deepEqual(result, targetArray,
"ensureIsAray with an array should return same array value.");
run_next_test();
});
add_test(function test_parseTLV_empty() {
let containerTags = [];
let result = null;
// Base:
result = SEUtils.parseTLV([], []);
deepEqual({}, result,
"empty parse input should result in an " +
"empty object (internal SEUtils format only).");
run_next_test();
});
add_test(function test_parseTLV_selectResponse() {
let result = null;
let hexStr = "62 27 82 02 78 21 83 02 7F 50 A5 06 83 04 00 04 C1 DC 8A" +
"01 05 8B 06 2F 06 01 16 00 14 C6 06 90 01 00 83 01 01 81" +
"02 FF FF";
let expected = {
0x62: {
0x82: [0x78, 0x21],
0x83: [0x7F, 0x50],
0xA5: {
0x83: [0x00, 0x04, 0xC1, 0xDC]
},
0x8A: [0x05],
0x8B: [0x2F, 0x06, 0x01, 0x16, 0x00, 0x14],
0xC6: [0x90, 0x01, 0x00, 0x83, 0x01, 0x01],
0x81: [0xFF, 0xFF]
}
};
result = SEUtils.parseTLV(formatHexAndCreateByteArray(hexStr), containerTags);
deepEqual(result, expected,
"parsed real selectResponse should equal the expected rules");
run_next_test();
});
add_test(function test_parseTLV_DODF() {
let result = null;
let hexStr = "A1 29 30 00 30 0F 0C 0D 47 50 20 53 45 20 41 63 63 20 43" +
"74 6C A1 14 30 12 06 0A 2A 86 48 86 FC 6B 81 48 01 01 30" +
"04 04 02 43 00 A1 2B 30 00 30 0F 0C 0D 53 41 54 53 41 20" +
"47 54 4F 20 31 2E 31 A1 16 30 14 06 0C 2B 06 01 04 01 2A" +
"02 6E 03 01 01 01 30 04 04 02 45 31 FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF";
let expected = {
0xA1: [
{
0x30: [
{},
{
0x0C: [0x47, 0x50, 0x20, 0x53, 0x45, 0x20, 0x41, 0x63, 0x63,
0x20, 0x43, 0x74, 0x6C]
}
],
0xA1: {
0x30: {
0x06: [0x2A, 0x86, 0x48, 0x86, 0xFC, 0x6B, 0x81, 0x48, 0x01,
0x01],
0x30: {
0x04: [0x43, 0x00]
}
}
}
},
{
0x30: [
{},
{
0x0C: [0x53, 0x41, 0x54, 0x53, 0x41, 0x20, 0x47, 0x54, 0x4F,
0x20, 0x31, 0x2E, 0x31]
}
],
0xA1: {
0x30: {
0x06: [0x2B, 0x06, 0x01, 0x04, 0x01, 0x2A, 0x02, 0x6E, 0x03,
0x01, 0x01, 0x01],
0x30: {
0x04: [0x45, 0x31]
}
}
}
}
]
};
result = SEUtils.parseTLV(formatHexAndCreateByteArray(hexStr), containerTags);
deepEqual(result, expected,
"Real Access Control Enforcer DODF file, with 0xFF padding. " +
"Should equal expected rules.");
run_next_test();
});
add_test(function test_parseTLV_acRules() {
let result = null;
let hexStr = "30 08 82 00 30 04 04 02 43 11 FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" +
"FF FF FF FF FF FF FF FF FF";
let expected = {
0x30: {
0x82: [],
0x30: {
0x04: [0x43, 0x11]
}
}
};
result = SEUtils.parseTLV(formatHexAndCreateByteArray(hexStr), containerTags);
deepEqual(result, expected,
"Parsed Access Control Rules should equal the expected rules");
run_next_test();
});

Просмотреть файл

@ -1,4 +0,0 @@
[DEFAULT]
head = header_helper.js
[test_SEUtils.js]

Просмотреть файл

@ -1,181 +0,0 @@
/* 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/. */
#include "nsIDocument.h"
#include "nsIDOMClassInfo.h"
#include "nsIDOMEvent.h"
#include "nsIDOMEventListener.h"
#include "nsPIDOMWindow.h"
#include "nsIDocShell.h"
#include "nsIPermissionManager.h"
#include "nsIInterfaceRequestorUtils.h"
#include "AudioChannelManager.h"
#include "mozilla/dom/AudioChannelManagerBinding.h"
#include "mozilla/dom/nsBrowserElement.h"
#include "mozilla/Services.h"
namespace mozilla {
namespace dom {
namespace system {
NS_IMPL_QUERY_INTERFACE_INHERITED(AudioChannelManager, DOMEventTargetHelper,
nsIDOMEventListener)
NS_IMPL_ADDREF_INHERITED(AudioChannelManager, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(AudioChannelManager, DOMEventTargetHelper)
AudioChannelManager::AudioChannelManager()
: mVolumeChannel(-1)
{
hal::RegisterSwitchObserver(hal::SWITCH_HEADPHONES, this);
}
AudioChannelManager::~AudioChannelManager()
{
hal::UnregisterSwitchObserver(hal::SWITCH_HEADPHONES, this);
nsCOMPtr<EventTarget> target = do_QueryInterface(GetOwner());
NS_ENSURE_TRUE_VOID(target);
target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
this,
/* useCapture = */ true);
}
void
AudioChannelManager::Init(nsPIDOMWindowInner* aWindow)
{
BindToOwner(aWindow);
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
NS_ENSURE_TRUE_VOID(target);
target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
this,
/* useCapture = */ true,
/* wantsUntrusted = */ false);
}
JSObject*
AudioChannelManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return AudioChannelManagerBinding::Wrap(aCx, this, aGivenProto);
}
void
AudioChannelManager::Notify(const hal::SwitchEvent& aEvent)
{
mState = Some(aEvent.status());
DispatchTrustedEvent(NS_LITERAL_STRING("headphoneschange"));
}
bool
AudioChannelManager::SetVolumeControlChannel(const nsAString& aChannel)
{
if (aChannel.EqualsASCII("publicnotification")) {
return false;
}
AudioChannel newChannel = AudioChannelService::GetAudioChannel(aChannel);
// Only normal channel doesn't need permission.
if (newChannel != AudioChannel::Normal) {
nsCOMPtr<nsIPermissionManager> permissionManager =
services::GetPermissionManager();
if (!permissionManager) {
return false;
}
uint32_t perm = nsIPermissionManager::UNKNOWN_ACTION;
permissionManager->TestPermissionFromWindow(GetOwner(),
nsCString(NS_LITERAL_CSTRING("audio-channel-") +
NS_ConvertUTF16toUTF8(aChannel)).get(), &perm);
if (perm != nsIPermissionManager::ALLOW_ACTION) {
return false;
}
}
if (mVolumeChannel == (int32_t)newChannel) {
return true;
}
mVolumeChannel = (int32_t)newChannel;
NotifyVolumeControlChannelChanged();
return true;
}
bool
AudioChannelManager::GetVolumeControlChannel(nsAString & aChannel)
{
if (mVolumeChannel >= 0) {
AudioChannelService::GetAudioChannelString(
static_cast<AudioChannel>(mVolumeChannel),
aChannel);
} else {
aChannel.AssignASCII("");
}
return true;
}
void
AudioChannelManager::NotifyVolumeControlChannelChanged()
{
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
NS_ENSURE_TRUE_VOID(docshell);
bool isActive = false;
docshell->GetIsActive(&isActive);
RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
if (!service) {
return;
}
if (isActive) {
service->SetDefaultVolumeControlChannel(mVolumeChannel, isActive);
} else {
service->SetDefaultVolumeControlChannel(-1, isActive);
}
}
NS_IMETHODIMP
AudioChannelManager::HandleEvent(nsIDOMEvent* aEvent)
{
nsAutoString type;
aEvent->GetType(type);
if (type.EqualsLiteral("visibilitychange")) {
NotifyVolumeControlChannelChanged();
}
return NS_OK;
}
void
AudioChannelManager::GetAllowedAudioChannels(
nsTArray<RefPtr<BrowserElementAudioChannel>>& aAudioChannels,
ErrorResult& aRv)
{
MOZ_ASSERT(aAudioChannels.IsEmpty());
// Only main process is supported.
if (XRE_GetProcessType() != GeckoProcessType_Default) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
if (NS_WARN_IF(!window)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsBrowserElement::GenerateAllowedAudioChannels(window, nullptr, nullptr,
aAudioChannels, aRv);
NS_WARNING_ASSERTION(!aRv.Failed(), "GenerateAllowedAudioChannels failed");
}
} // namespace system
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -1,87 +0,0 @@
/* 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_dom_system_AudioChannelManager_h
#define mozilla_dom_system_AudioChannelManager_h
#include "mozilla/dom/BrowserElementAudioChannel.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/Hal.h"
#include "mozilla/HalTypes.h"
#include "mozilla/Maybe.h"
#include "AudioChannelService.h"
namespace mozilla {
namespace hal {
class SwitchEvent;
typedef Observer<SwitchEvent> SwitchObserver;
} // namespace hal
namespace dom {
namespace system {
class AudioChannelManager final
: public DOMEventTargetHelper
, public hal::SwitchObserver
, public nsIDOMEventListener
{
public:
AudioChannelManager();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMEVENTLISTENER
void Notify(const hal::SwitchEvent& aEvent);
void Init(nsPIDOMWindowInner* aWindow);
/**
* WebIDL Interface
*/
nsPIDOMWindowInner* GetParentObject() const
{
return GetOwner();
}
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
bool Headphones()
{
// Bug 929139 - Remove the assert check for SWITCH_STATE_UNKNOWN.
// If any devices (ex: emulator) didn't have the corresponding sys node for
// headset switch state then GonkSwitch will report the unknown state.
// So it is possible to get unknown state here.
if (mState.isNothing()) {
mState = Some(hal::GetCurrentSwitchState(hal::SWITCH_HEADPHONES));
}
return mState.value() != hal::SWITCH_STATE_OFF &&
mState.value() != hal::SWITCH_STATE_UNKNOWN;
}
bool SetVolumeControlChannel(const nsAString& aChannel);
bool GetVolumeControlChannel(nsAString& aChannel);
IMPL_EVENT_HANDLER(headphoneschange)
void GetAllowedAudioChannels(
nsTArray<RefPtr<mozilla::dom::BrowserElementAudioChannel>>& aAudioChannels,
mozilla::ErrorResult& aRv);
protected:
virtual ~AudioChannelManager();
private:
void NotifyVolumeControlChannelChanged();
Maybe<hal::SwitchState> mState;
int32_t mVolumeChannel;
};
} // namespace system
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_system_AudioChannelManager_h

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,180 +0,0 @@
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
*
* 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.
*/
#ifndef mozilla_dom_system_b2g_audiomanager_h__
#define mozilla_dom_system_b2g_audiomanager_h__
#include "mozilla/HalTypes.h"
#include "mozilla/Observer.h"
#include "mozilla/UniquePtr.h"
#include "nsAutoPtr.h"
#include "nsDataHashtable.h"
#include "nsIAudioManager.h"
#include "nsIObserver.h"
#include "android_audio/AudioSystem.h"
// {b2b51423-502d-4d77-89b3-7786b562b084}
#define NS_AUDIOMANAGER_CID {0x94f6fd70, 0x7615, 0x4af9, \
{0x89, 0x10, 0xf9, 0x3c, 0x55, 0xe6, 0x62, 0xec}}
#define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1"
class nsISettingsServiceLock;
namespace mozilla {
namespace hal {
class SwitchEvent;
typedef Observer<SwitchEvent> SwitchObserver;
} // namespace hal
namespace dom {
namespace gonk {
class VolumeInitCallback;
class AudioManager final : public nsIAudioManager
, public nsIObserver
{
public:
static already_AddRefed<AudioManager> GetInstance();
NS_DECL_ISUPPORTS
NS_DECL_NSIAUDIOMANAGER
NS_DECL_NSIOBSERVER
// Validate whether the volume index is within the range
nsresult ValidateVolumeIndex(int32_t aStream, uint32_t aIndex) const;
// Called when android AudioFlinger in mediaserver is died
void HandleAudioFlingerDied();
void HandleHeadphoneSwitchEvent(const hal::SwitchEvent& aEvent);
class VolumeStreamState {
public:
explicit VolumeStreamState(AudioManager& aManager, int32_t aStreamType);
int32_t GetStreamType()
{
return mStreamType;
}
bool IsDevicesChanged(bool aFromCache = true);
void ClearDevicesChanged();
uint32_t GetLastDevices()
{
return mLastDevices;
}
bool IsVolumeIndexesChanged();
void ClearVolumeIndexesChanged();
void InitStreamVolume();
uint32_t GetMaxIndex();
uint32_t GetDefaultIndex();
uint32_t GetVolumeIndex();
uint32_t GetVolumeIndex(uint32_t aDevice);
void ClearCurrentVolumeUpdated();
// Set volume index to all active devices.
// Active devices are chosen by android AudioPolicyManager.
nsresult SetVolumeIndexToActiveDevices(uint32_t aIndex);
// Set volume index to all alias streams for device. Alias streams have same volume.
nsresult SetVolumeIndexToAliasStreams(uint32_t aIndex, uint32_t aDevice);
nsresult SetVolumeIndexToConsistentDeviceIfNeeded(uint32_t aIndex, uint32_t aDevice);
nsresult SetVolumeIndex(uint32_t aIndex, uint32_t aDevice, bool aUpdateCache = true);
// Restore volume index to all devices. Called when AudioFlinger is restarted.
void RestoreVolumeIndexToAllDevices();
private:
AudioManager& mManager;
const int32_t mStreamType;
uint32_t mLastDevices;
bool mIsDevicesChanged;
bool mIsVolumeIndexesChanged;
nsDataHashtable<nsUint32HashKey, uint32_t> mVolumeIndexes;
};
protected:
int32_t mPhoneState;
bool mIsVolumeInited;
// A bitwise variable for volume update of audio output devices,
// clear it after store the value into database.
uint32_t mAudioOutDevicesUpdated;
// Connected devices that are controlled by setDeviceConnectionState()
nsDataHashtable<nsUint32HashKey, nsCString> mConnectedDevices;
nsDataHashtable<nsUint32HashKey, uint32_t> mAudioDeviceTableIdMaps;
bool mSwitchDone;
#if defined(MOZ_B2G_BT) || ANDROID_VERSION >= 17
bool mBluetoothA2dpEnabled;
#endif
#ifdef MOZ_B2G_BT
bool mA2dpSwitchDone;
#endif
nsTArray<UniquePtr<VolumeStreamState> > mStreamStates;
uint32_t mLastChannelVolume[AUDIO_STREAM_CNT];
bool IsFmOutConnected();
nsresult SetStreamVolumeForDevice(int32_t aStream,
uint32_t aIndex,
uint32_t aDevice);
nsresult SetStreamVolumeIndex(int32_t aStream, uint32_t aIndex);
nsresult GetStreamVolumeIndex(int32_t aStream, uint32_t* aIndex);
void UpdateCachedActiveDevicesForStreams();
uint32_t GetDevicesForStream(int32_t aStream, bool aFromCache = true);
uint32_t GetDeviceForStream(int32_t aStream);
// Choose one device as representative of active devices.
static uint32_t SelectDeviceFromDevices(uint32_t aOutDevices);
private:
nsAutoPtr<mozilla::hal::SwitchObserver> mObserver;
void HandleBluetoothStatusChanged(nsISupports* aSubject,
const char* aTopic,
const nsCString aAddress);
void HandleAudioChannelProcessChanged();
// Append the audio output device to the volume setting string.
nsAutoCString AppendDeviceToVolumeSetting(const char* aName,
uint32_t aDevice);
// We store the volume setting in the database, these are related functions.
void InitVolumeFromDatabase();
void MaybeUpdateVolumeSettingToDatabase(bool aForce = false);
// Promise functions.
void InitDeviceVolumeSucceeded();
void InitDeviceVolumeFailed(const char* aError);
void AudioOutDeviceUpdated(uint32_t aDevice);
void UpdateHeadsetConnectionState(hal::SwitchState aState);
void UpdateDeviceConnectionState(bool aIsConnected, uint32_t aDevice, const nsCString& aDeviceName);
void SetAllDeviceConnectionStates();
AudioManager();
~AudioManager();
friend class VolumeInitCallback;
friend class VolumeStreamState;
friend class GonkAudioPortCallback;
};
} /* namespace gonk */
} /* namespace dom */
} /* namespace mozilla */
#endif // mozilla_dom_system_b2g_audiomanager_h__

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,101 +0,0 @@
/* 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_automounter_h__
#define mozilla_system_automounter_h__
#include <stdint.h>
class nsCString;
namespace mozilla {
namespace system {
// AutoMounter modes
#define AUTOMOUNTER_DISABLE 0
#define AUTOMOUNTER_ENABLE_UMS 1
#define AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED 2
#define AUTOMOUNTER_ENABLE_MTP 3
// Automounter statuses
#define AUTOMOUNTER_STATUS_DISABLED 0
#define AUTOMOUNTER_STATUS_ENABLED 1
#define AUTOMOUNTER_STATUS_FILES_OPEN 2
/**
* Initialize the automounter. This causes some of the phone's
* directories to show up on the host when the phone is plugged
* into the host via USB.
*
* When the AutoMounter starts, it will poll the current state
* of affairs (usb cable plugged in, automounter enabled, etc)
* and try to make the state of the volumes match.
*/
void
InitAutoMounter();
/**
* Sets the enabled state of the automounter.
*
* This will in turn cause the automounter to re-evaluate
* whether it should mount/unmount/share/unshare volumes.
*/
void
SetAutoMounterMode(int32_t aMode);
/**
* Reports the status of the automounter.
*/
int32_t
GetAutoMounterStatus();
/**
* Sets the sharing mode of an individual volume.
*
* If a volume is enabled for sharing, and the autmounter
* is in a state to share, then the volume will be shared
* with the PC.
*/
void
SetAutoMounterSharingMode(const nsCString& aVolumeName, bool aAllowSharing);
/**
* Formats the volume with specified volume name.
*
* If the volume is ready to format, automounter
* will unmount it, format it and then mount it again.
*/
void
AutoMounterFormatVolume(const nsCString& aVolumeName);
/**
* Mounts the volume with specified volume name.
*
* If the volume is already unmounted, automounter
* will mount it. Otherwise automounter will skip this.
*/
void
AutoMounterMountVolume(const nsCString& aVolumeName);
/**
* Unmounts the volume with specified volume name.
*
* If the volume is already mounted, automounter
* will unmount it. Otherwise automounter will skip this.
*/
void
AutoMounterUnmountVolume(const nsCString& aVolumeName);
/**
* Shuts down the automounter.
*
* This leaves the volumes in whatever state they're in.
*/
void
ShutdownAutoMounter();
} // system
} // mozilla
#endif // mozilla_system_automounter_h__

Просмотреть файл

@ -1,284 +0,0 @@
/* 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/. */
#include "AutoMounter.h"
#include "AutoMounterSetting.h"
#include "base/message_loop.h"
#include "jsapi.h"
#include "mozilla/Services.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nsDebug.h"
#include "nsIObserverService.h"
#include "nsISettingsService.h"
#include "nsJSUtils.h"
#include "nsPrintfCString.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsThreadUtils.h"
#include "xpcpublic.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/SettingChangeNotificationBinding.h"
#undef LOG
#undef ERR
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AutoMounterSetting" , ## args)
#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "AutoMounterSetting" , ## args)
#define UMS_MODE "ums.mode"
#define UMS_STATUS "ums.status"
#define UMS_VOLUME_ENABLED_PREFIX "ums.volume."
#define UMS_VOLUME_ENABLED_SUFFIX ".enabled"
#define MOZSETTINGS_CHANGED "mozsettings-changed"
using namespace mozilla::dom;
namespace mozilla {
namespace system {
class SettingsServiceCallback final : public nsISettingsServiceCallback
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
SettingsServiceCallback() {}
NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult)
{
if (aResult.isInt32()) {
int32_t mode = aResult.toInt32();
SetAutoMounterMode(mode);
}
return NS_OK;
}
NS_IMETHOD HandleError(const nsAString& aName)
{
ERR("SettingsCallback::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get());
return NS_OK;
}
protected:
~SettingsServiceCallback() {}
};
NS_IMPL_ISUPPORTS(SettingsServiceCallback, nsISettingsServiceCallback)
class CheckVolumeSettingsCallback final : public nsISettingsServiceCallback
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
CheckVolumeSettingsCallback(const nsACString& aVolumeName)
: mVolumeName(aVolumeName) {}
NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult)
{
if (aResult.isBoolean()) {
bool isSharingEnabled = aResult.toBoolean();
SetAutoMounterSharingMode(mVolumeName, isSharingEnabled);
}
return NS_OK;
}
NS_IMETHOD HandleError(const nsAString& aName)
{
ERR("CheckVolumeSettingsCallback::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get());
return NS_OK;
}
protected:
~CheckVolumeSettingsCallback() {}
private:
nsCString mVolumeName;
};
NS_IMPL_ISUPPORTS(CheckVolumeSettingsCallback, nsISettingsServiceCallback)
AutoMounterSetting::AutoMounterSetting()
: mStatus(AUTOMOUNTER_STATUS_DISABLED)
{
MOZ_ASSERT(NS_IsMainThread());
// Setup an observer to watch changes to the setting
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (!observerService) {
ERR("GetObserverService failed");
return;
}
nsresult rv;
rv = observerService->AddObserver(this, MOZSETTINGS_CHANGED, false);
if (NS_FAILED(rv)) {
ERR("AddObserver failed");
return;
}
// Force ums.mode to be 0 initially. We do this because settings are persisted.
// We don't want UMS to be enabled until such time as the phone is unlocked,
// and gaia/apps/system/js/storage.js takes care of detecting when the phone
// becomes unlocked and changes ums.mode appropriately.
nsCOMPtr<nsISettingsService> settingsService =
do_GetService("@mozilla.org/settingsService;1");
if (!settingsService) {
ERR("Failed to get settingsLock service!");
return;
}
nsCOMPtr<nsISettingsServiceLock> lock;
settingsService->CreateLock(nullptr, getter_AddRefs(lock));
nsCOMPtr<nsISettingsServiceCallback> callback = new SettingsServiceCallback();
JS::Rooted<JS::Value> value(RootingCx());
value.setInt32(AUTOMOUNTER_DISABLE);
lock->Set(UMS_MODE, value, callback, nullptr);
value.setInt32(mStatus);
lock->Set(UMS_STATUS, value, nullptr, nullptr);
}
AutoMounterSetting::~AutoMounterSetting()
{
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
observerService->RemoveObserver(this, MOZSETTINGS_CHANGED);
}
}
NS_IMPL_ISUPPORTS(AutoMounterSetting, nsIObserver)
const char *
AutoMounterSetting::StatusStr(int32_t aStatus)
{
switch (aStatus) {
case AUTOMOUNTER_STATUS_DISABLED: return "Disabled";
case AUTOMOUNTER_STATUS_ENABLED: return "Enabled";
case AUTOMOUNTER_STATUS_FILES_OPEN: return "FilesOpen";
}
return "??? Unknown ???";
}
class CheckVolumeSettingsRunnable : public Runnable
{
public:
CheckVolumeSettingsRunnable(const nsACString& aVolumeName)
: mVolumeName(aVolumeName) {}
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsISettingsService> settingsService =
do_GetService("@mozilla.org/settingsService;1");
NS_ENSURE_TRUE(settingsService, NS_ERROR_FAILURE);
nsCOMPtr<nsISettingsServiceLock> lock;
settingsService->CreateLock(nullptr, getter_AddRefs(lock));
nsCOMPtr<nsISettingsServiceCallback> callback =
new CheckVolumeSettingsCallback(mVolumeName);
nsPrintfCString setting(UMS_VOLUME_ENABLED_PREFIX "%s" UMS_VOLUME_ENABLED_SUFFIX,
mVolumeName.get());
lock->Get(setting.get(), callback);
return NS_OK;
}
private:
nsCString mVolumeName;
};
//static
void
AutoMounterSetting::CheckVolumeSettings(const nsACString& aVolumeName)
{
NS_DispatchToMainThread(new CheckVolumeSettingsRunnable(aVolumeName));
}
class SetStatusRunnable : public Runnable
{
public:
SetStatusRunnable(int32_t aStatus) : mStatus(aStatus) {}
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsISettingsService> settingsService =
do_GetService("@mozilla.org/settingsService;1");
NS_ENSURE_TRUE(settingsService, NS_ERROR_FAILURE);
nsCOMPtr<nsISettingsServiceLock> lock;
settingsService->CreateLock(nullptr, getter_AddRefs(lock));
// lock may be null if this gets called during shutdown.
if (lock) {
JS::Rooted<JS::Value> value(RootingCx(),
JS::Int32Value(mStatus));
lock->Set(UMS_STATUS, value, nullptr, nullptr);
}
return NS_OK;
}
private:
int32_t mStatus;
};
//static
void
AutoMounterSetting::SetStatus(int32_t aStatus)
{
if (aStatus != mStatus) {
LOG("Changing status from '%s' to '%s'",
StatusStr(mStatus), StatusStr(aStatus));
mStatus = aStatus;
NS_DispatchToMainThread(new SetStatusRunnable(aStatus));
}
}
NS_IMETHODIMP
AutoMounterSetting::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
if (strcmp(aTopic, MOZSETTINGS_CHANGED) != 0) {
return NS_OK;
}
// Note that this function gets called for any and all settings changes,
// so we need to carefully check if we have the one we're interested in.
//
// The string that we're interested in will be a JSON string that looks like:
// {"key":"ums.autoMount","value":true}
RootedDictionary<SettingChangeNotification> setting(RootingCx());
if (!WrappedJSToDictionary(aSubject, setting)) {
return NS_OK;
}
// Check for ums.mode changes
if (setting.mKey.EqualsASCII(UMS_MODE)) {
if (!setting.mValue.isInt32()) {
return NS_OK;
}
int32_t mode = setting.mValue.toInt32();
SetAutoMounterMode(mode);
return NS_OK;
}
// Check for ums.volume.NAME.enabled
if (StringBeginsWith(setting.mKey, NS_LITERAL_STRING(UMS_VOLUME_ENABLED_PREFIX)) &&
StringEndsWith(setting.mKey, NS_LITERAL_STRING(UMS_VOLUME_ENABLED_SUFFIX))) {
if (!setting.mValue.isBoolean()) {
return NS_OK;
}
const size_t prefixLen = sizeof(UMS_VOLUME_ENABLED_PREFIX) - 1;
const size_t suffixLen = sizeof(UMS_VOLUME_ENABLED_SUFFIX) - 1;
nsDependentSubstring volumeName =
Substring(setting.mKey, prefixLen, setting.mKey.Length() - prefixLen - suffixLen);
bool isSharingEnabled = setting.mValue.toBoolean();
SetAutoMounterSharingMode(NS_LossyConvertUTF16toASCII(volumeName), isSharingEnabled);
return NS_OK;
}
return NS_OK;
}
} // namespace system
} // namespace mozilla

Просмотреть файл

@ -1,38 +0,0 @@
/* 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_automountersetting_h__
#define mozilla_system_automountersetting_h__
#include "nsIObserver.h"
namespace mozilla {
namespace system {
class AutoMounterSetting : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
AutoMounterSetting();
static void CheckVolumeSettings(const nsACString& aVolumeName);
int32_t GetStatus() { return mStatus; }
void SetStatus(int32_t aStatus);
const char *StatusStr(int32_t aStatus);
protected:
virtual ~AutoMounterSetting();
private:
int32_t mStatus;
};
} // namespace system
} // namespace mozilla
#endif // mozilla_system_automountersetting_h__

Просмотреть файл

@ -1,271 +0,0 @@
/* 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/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const DATACALLINTERFACE_CONTRACTID = "@mozilla.org/datacall/interface;1";
const DATACALLINTERFACESERVICE_CONTRACTID =
"@mozilla.org/datacall/interfaceservice;1";
const DATACALLINTERFACE_CID =
Components.ID("{ff669306-4390-462a-989b-ba37fc42153f}");
const DATACALLINTERFACESERVICE_CID =
Components.ID("{e23e9337-592d-40b9-8cef-7bd47c28b72e}");
const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown";
const TOPIC_PREF_CHANGED = "nsPref:changed";
const PREF_RIL_DEBUG_ENABLED = "ril.debugging.enabled";
XPCOMUtils.defineLazyGetter(this, "RIL", function () {
let obj = {};
Cu.import("resource://gre/modules/ril_consts.js", obj);
return obj;
});
XPCOMUtils.defineLazyServiceGetter(this, "gRil",
"@mozilla.org/ril;1",
"nsIRadioInterfaceLayer");
XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
"nsIMobileConnectionService");
var DEBUG = RIL.DEBUG_RIL;
function updateDebugFlag() {
// Read debug setting from pref
let debugPref = Services.prefs.getBoolPref(PREF_RIL_DEBUG_ENABLED, false);
DEBUG = debugPref || RIL.DEBUG_RIL;
}
updateDebugFlag();
function DataCall(aAttributes) {
for (let key in aAttributes) {
if (key === "pdpType") {
// Convert pdp type into constant int value.
this[key] = RIL.RIL_DATACALL_PDP_TYPES.indexOf(aAttributes[key]);
continue;
}
this[key] = aAttributes[key];
}
}
DataCall.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCall]),
failCause: Ci.nsIDataCallInterface.DATACALL_FAIL_NONE,
suggestedRetryTime: -1,
cid: -1,
active: -1,
pdpType: -1,
ifname: null,
addreses: null,
dnses: null,
gateways: null,
pcscf: null,
mtu: -1
};
function DataCallInterfaceService() {
this._dataCallInterfaces = [];
let numClients = gRil.numRadioInterfaces;
for (let i = 0; i < numClients; i++) {
this._dataCallInterfaces.push(new DataCallInterface(i));
}
Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN);
Services.prefs.addObserver(PREF_RIL_DEBUG_ENABLED, this);
}
DataCallInterfaceService.prototype = {
classID: DATACALLINTERFACESERVICE_CID,
classInfo: XPCOMUtils.generateCI({
classID: DATACALLINTERFACESERVICE_CID,
contractID: DATACALLINTERFACESERVICE_CONTRACTID,
classDescription: "Data Call Interface Service",
interfaces: [Ci.nsIDataCallInterfaceService,
Ci.nsIGonkDataCallInterfaceService]
}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallInterfaceService,
Ci.nsIGonkDataCallInterfaceService],
Ci.nsIObserver),
// An array of DataCallInterface instances.
_dataCallInterfaces: null,
debug: function(aMessage) {
dump("-*- DataCallInterfaceService: " + aMessage + "\n");
},
// nsIDataCallInterfaceService
getDataCallInterface: function(aClientId) {
let dataCallInterface = this._dataCallInterfaces[aClientId];
if (!dataCallInterface) {
throw Cr.NS_ERROR_UNEXPECTED;
}
return dataCallInterface;
},
// nsIGonkDataCallInterfaceService
notifyDataCallListChanged: function(aClientId, aCount, aDataCalls) {
let dataCallInterface = this.getDataCallInterface(aClientId);
dataCallInterface.handleDataCallListChanged(aCount, aDataCalls);
},
// nsIObserver
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case TOPIC_PREF_CHANGED:
if (aData === PREF_RIL_DEBUG_ENABLED) {
updateDebugFlag();
}
break;
case TOPIC_XPCOM_SHUTDOWN:
Services.prefs.removeObserver(PREF_RIL_DEBUG_ENABLED, this);
Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
break;
}
},
};
function DataCallInterface(aClientId) {
this._clientId = aClientId;
this._radioInterface = gRil.getRadioInterface(aClientId);
this._listeners = [];
if (DEBUG) this.debug("DataCallInterface: " + aClientId);
}
DataCallInterface.prototype = {
classID: DATACALLINTERFACE_CID,
classInfo: XPCOMUtils.generateCI({classID: DATACALLINTERFACE_CID,
contractID: DATACALLINTERFACE_CONTRACTID,
classDescription: "Data Call Interface",
interfaces: [Ci.nsIDataCallInterface]}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallInterface]),
debug: function(aMessage) {
dump("-*- DataCallInterface[" + this._clientId + "]: " + aMessage + "\n");
},
_clientId: -1,
_radioInterface: null,
_listeners: null,
// nsIDataCallInterface
setupDataCall: function(aApn, aUsername, aPassword, aAuthType, aPdpType,
aCallback) {
let connection =
gMobileConnectionService.getItemByServiceId(this._clientId);
let dataInfo = connection && connection.data;
let radioTechType = dataInfo.type;
let radioTechnology = RIL.GECKO_RADIO_TECH.indexOf(radioTechType);
// Convert pdp type into string value.
let pdpType = RIL.RIL_DATACALL_PDP_TYPES[aPdpType];
this._radioInterface.sendWorkerMessage("setupDataCall", {
radioTech: radioTechnology,
apn: aApn,
user: aUsername,
passwd: aPassword,
chappap: aAuthType,
pdptype: pdpType
}, (aResponse) => {
if (aResponse.errorMsg) {
aCallback.notifyError(aResponse.errorMsg);
} else {
let dataCall = new DataCall(aResponse);
aCallback.notifySetupDataCallSuccess(dataCall);
}
});
},
deactivateDataCall: function(aCid, aReason, aCallback) {
this._radioInterface.sendWorkerMessage("deactivateDataCall", {
cid: aCid,
reason: aReason
}, (aResponse) => {
if (aResponse.errorMsg) {
aCallback.notifyError(aResponse.errorMsg);
} else {
aCallback.notifySuccess();
}
});
},
getDataCallList: function(aCallback) {
this._radioInterface.sendWorkerMessage("getDataCallList", null,
(aResponse) => {
if (aResponse.errorMsg) {
aCallback.notifyError(aResponse.errorMsg);
} else {
let dataCalls = aResponse.datacalls.map(
dataCall => new DataCall(dataCall));
aCallback.notifyGetDataCallListSuccess(dataCalls.length, dataCalls);
}
});
},
setDataRegistration: function(aAttach, aCallback) {
this._radioInterface.sendWorkerMessage("setDataRegistration", {
attach: aAttach
}, (aResponse) => {
if (aResponse.errorMsg) {
aCallback.notifyError(aResponse.errorMsg);
} else {
aCallback.notifySuccess();
}
});
},
handleDataCallListChanged: function(aCount, aDataCalls) {
this._notifyAllListeners("notifyDataCallListChanged", [aCount, aDataCalls]);
},
_notifyAllListeners: function(aMethodName, aArgs) {
let listeners = this._listeners.slice();
for (let listener of listeners) {
if (this._listeners.indexOf(listener) == -1) {
// Listener has been unregistered in previous run.
continue;
}
let handler = listener[aMethodName];
try {
handler.apply(listener, aArgs);
} catch (e) {
if (DEBUG) {
this.debug("listener for " + aMethodName + " threw an exception: " + e);
}
}
}
},
registerListener: function(aListener) {
if (this._listeners.indexOf(aListener) >= 0) {
return;
}
this._listeners.push(aListener);
},
unregisterListener: function(aListener) {
let index = this._listeners.indexOf(aListener);
if (index >= 0) {
this._listeners.splice(index, 1);
}
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataCallInterfaceService]);

Просмотреть файл

@ -1,6 +0,0 @@
# 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/.
component {e23e9337-592d-40b9-8cef-7bd47c28b72e} DataCallInterfaceService.js
contract @mozilla.org/datacall/interfaceservice;1 {e23e9337-592d-40b9-8cef-7bd47c28b72e}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,4 +0,0 @@
# DataCallManager.js
component {35b9efa2-e42c-45ce-8210-0a13e6f4aadc} DataCallManager.js
contract @mozilla.org/datacall/manager;1 {35b9efa2-e42c-45ce-8210-0a13e6f4aadc}
category profile-after-change DataCallManager @mozilla.org/datacall/manager;1

Просмотреть файл

@ -1,28 +0,0 @@
/* -*- 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/. */
#include "GeolocationUtil.h"
double CalculateDeltaInMeter(double aLat, double aLon, double aLastLat, double aLastLon)
{
// Use spherical law of cosines to calculate difference
// Not quite as correct as the Haversine but simpler and cheaper
const double radsInDeg = M_PI / 180.0;
const double rNewLat = aLat * radsInDeg;
const double rNewLon = aLon * radsInDeg;
const double rOldLat = aLastLat * radsInDeg;
const double rOldLon = aLastLon * radsInDeg;
// WGS84 equatorial radius of earth = 6378137m
double cosDelta = (sin(rNewLat) * sin(rOldLat)) +
(cos(rNewLat) * cos(rOldLat) * cos(rOldLon - rNewLon));
if (cosDelta > 1.0) {
cosDelta = 1.0;
} else if (cosDelta < -1.0) {
cosDelta = -1.0;
}
return acos(cosDelta) * 6378137;
}

Просмотреть файл

@ -1,13 +0,0 @@
/* -*- 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 GEOLOCATIONUTIL_H
#define GEOLOCATIONUTIL_H
double CalculateDeltaInMeter(double aLat, double aLon, double aLastLat, double aLastLon);
#endif

Просмотреть файл

@ -1,706 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
*
* 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 "GonkGPSGeolocationProvider.h"
#include <cmath>
#include <pthread.h>
#include <hardware/gps.h>
#include "base/task.h"
#include "GeolocationUtil.h"
#include "mozstumbler/MozStumbler.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "nsContentUtils.h"
#include "nsGeoPosition.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsINetworkInterface.h"
#include "nsIObserverService.h"
#include "nsJSUtils.h"
#include "nsPrintfCString.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "prtime.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/SettingChangeNotificationBinding.h"
#ifdef AGPS_TYPE_INVALID
#define AGPS_HAVE_DUAL_APN
#endif
#define FLUSH_AIDE_DATA 0
#undef LOG
#undef ERR
#undef DBG
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkGPSGeolocationProvider", ## args)
#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "GonkGPSGeolocationProvider", ## args)
#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, "GonkGPSGeolocationProvider" , ## args)
using namespace mozilla;
using namespace mozilla::dom;
static const int kDefaultPeriod = 1000; // ms
static bool gDebug_isLoggingEnabled = false;
static bool gDebug_isGPSLocationIgnored = false;
static const char* kMozSettingsChangedTopic = "mozsettings-changed";
// Both of these settings can be toggled in the Gaia Developer settings screen.
static const char* kSettingDebugEnabled = "geolocation.debugging.enabled";
static const char* kSettingDebugGpsIgnored = "geolocation.debugging.gps-locations-ignored";
// While most methods of GonkGPSGeolocationProvider should only be
// called from main thread, we deliberately put the Init and ShutdownGPS
// methods off main thread to avoid blocking.
NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider,
nsIGeolocationProvider,
nsIObserver,
nsISettingsServiceCallback)
/* static */ GonkGPSGeolocationProvider* GonkGPSGeolocationProvider::sSingleton = nullptr;
GpsCallbacks GonkGPSGeolocationProvider::mCallbacks;
void
GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location)
{
if (gDebug_isGPSLocationIgnored) {
return;
}
class UpdateLocationEvent : public Runnable {
public:
UpdateLocationEvent(nsGeoPosition* aPosition)
: mPosition(aPosition)
{}
NS_IMETHOD Run() override {
RefPtr<GonkGPSGeolocationProvider> provider =
GonkGPSGeolocationProvider::GetSingleton();
nsCOMPtr<nsIGeolocationUpdate> callback = provider->mLocationCallback;
provider->mLastGPSPosition = mPosition;
if (callback) {
callback->Update(mPosition);
}
return NS_OK;
}
private:
RefPtr<nsGeoPosition> mPosition;
};
MOZ_ASSERT(location);
const float kImpossibleAccuracy_m = 0.001;
if (location->accuracy < kImpossibleAccuracy_m) {
return;
}
RefPtr<nsGeoPosition> somewhere = new nsGeoPosition(location->latitude,
location->longitude,
location->altitude,
location->accuracy,
location->accuracy,
location->bearing,
location->speed,
PR_Now() / PR_USEC_PER_MSEC);
// Note above: Can't use location->timestamp as the time from the satellite is a
// minimum of 16 secs old (see http://leapsecond.com/java/gpsclock.htm).
// All code from this point on expects the gps location to be timestamped with the
// current time, most notably: the geolocation service which respects maximumAge
// set in the DOM JS.
if (gDebug_isLoggingEnabled) {
DBG("geo: GPS got a fix (%f, %f). accuracy: %f",
location->latitude,
location->longitude,
location->accuracy);
}
RefPtr<UpdateLocationEvent> event = new UpdateLocationEvent(somewhere);
NS_DispatchToMainThread(event);
}
class NotifyObserversGPSTask final : public Runnable
{
public:
explicit NotifyObserversGPSTask(const char16_t* aData)
: mData(aData)
{}
NS_IMETHOD Run() override {
RefPtr<nsIGeolocationProvider> provider =
GonkGPSGeolocationProvider::GetSingleton();
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
obsService->NotifyObservers(provider, "geolocation-device-events", mData);
return NS_OK;
}
private:
const char16_t* mData;
};
void
GonkGPSGeolocationProvider::StatusCallback(GpsStatus* status)
{
const char* msgStream=0;
switch (status->status) {
case GPS_STATUS_NONE:
msgStream = "geo: GPS_STATUS_NONE\n";
break;
case GPS_STATUS_SESSION_BEGIN:
msgStream = "geo: GPS_STATUS_SESSION_BEGIN\n";
break;
case GPS_STATUS_SESSION_END:
msgStream = "geo: GPS_STATUS_SESSION_END\n";
break;
case GPS_STATUS_ENGINE_ON:
msgStream = "geo: GPS_STATUS_ENGINE_ON\n";
NS_DispatchToMainThread(new NotifyObserversGPSTask(u"GPSStarting"));
break;
case GPS_STATUS_ENGINE_OFF:
msgStream = "geo: GPS_STATUS_ENGINE_OFF\n";
NS_DispatchToMainThread(new NotifyObserversGPSTask(u"GPSShutdown"));
break;
default:
msgStream = "geo: Unknown GPS status\n";
break;
}
if (gDebug_isLoggingEnabled){
DBG("%s", msgStream);
}
}
void
GonkGPSGeolocationProvider::SvStatusCallback(GpsSvStatus* sv_info)
{
if (gDebug_isLoggingEnabled) {
static int numSvs = 0;
static uint32_t numEphemeris = 0;
static uint32_t numAlmanac = 0;
static uint32_t numUsedInFix = 0;
unsigned int i = 1;
uint32_t svAlmanacCount = 0;
for (i = 1; i > 0; i <<= 1) {
if (i & sv_info->almanac_mask) {
svAlmanacCount++;
}
}
uint32_t svEphemerisCount = 0;
for (i = 1; i > 0; i <<= 1) {
if (i & sv_info->ephemeris_mask) {
svEphemerisCount++;
}
}
uint32_t svUsedCount = 0;
for (i = 1; i > 0; i <<= 1) {
if (i & sv_info->used_in_fix_mask) {
svUsedCount++;
}
}
// Log the message only if the the status changed.
if (sv_info->num_svs != numSvs ||
svAlmanacCount != numAlmanac ||
svEphemerisCount != numEphemeris ||
svUsedCount != numUsedInFix) {
LOG(
"geo: Number of SVs have (visibility, almanac, ephemeris): (%d, %d, %d)."
" %d of these SVs were used in fix.\n",
sv_info->num_svs, svAlmanacCount, svEphemerisCount, svUsedCount);
numSvs = sv_info->num_svs;
numAlmanac = svAlmanacCount;
numEphemeris = svEphemerisCount;
numUsedInFix = svUsedCount;
}
}
}
void
GonkGPSGeolocationProvider::NmeaCallback(GpsUtcTime timestamp, const char* nmea, int length)
{
if (gDebug_isLoggingEnabled) {
DBG("NMEA: timestamp:\t%lld, length: %d, %s", timestamp, length, nmea);
}
}
void
GonkGPSGeolocationProvider::SetCapabilitiesCallback(uint32_t capabilities)
{
class UpdateCapabilitiesEvent : public Runnable {
public:
UpdateCapabilitiesEvent(uint32_t aCapabilities)
: mCapabilities(aCapabilities)
{}
NS_IMETHOD Run() override {
RefPtr<GonkGPSGeolocationProvider> provider =
GonkGPSGeolocationProvider::GetSingleton();
provider->mSupportsScheduling = mCapabilities & GPS_CAPABILITY_SCHEDULING;
provider->mSupportsSingleShot = mCapabilities & GPS_CAPABILITY_SINGLE_SHOT;
#ifdef GPS_CAPABILITY_ON_DEMAND_TIME
provider->mSupportsTimeInjection = mCapabilities & GPS_CAPABILITY_ON_DEMAND_TIME;
#endif
return NS_OK;
}
private:
uint32_t mCapabilities;
};
NS_DispatchToMainThread(new UpdateCapabilitiesEvent(capabilities));
}
void
GonkGPSGeolocationProvider::AcquireWakelockCallback()
{
}
void
GonkGPSGeolocationProvider::ReleaseWakelockCallback()
{
}
typedef void *(*pthread_func)(void *);
/** Callback for creating a thread that can call into the JS codes.
*/
pthread_t
GonkGPSGeolocationProvider::CreateThreadCallback(const char* name, void (*start)(void *), void* arg)
{
pthread_t thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
/* Unfortunately pthread_create and the callback disagreed on what
* start function should return.
*/
pthread_create(&thread, &attr, reinterpret_cast<pthread_func>(start), arg);
return thread;
}
void
GonkGPSGeolocationProvider::RequestUtcTimeCallback()
{
}
GonkGPSGeolocationProvider::GonkGPSGeolocationProvider()
: mStarted(false)
, mSupportsScheduling(false)
, mObservingSettingsChange(false)
, mSupportsSingleShot(false)
, mSupportsTimeInjection(false)
, mGpsInterface(nullptr)
{
}
GonkGPSGeolocationProvider::~GonkGPSGeolocationProvider()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mStarted, "Must call Shutdown before destruction");
sSingleton = nullptr;
}
already_AddRefed<GonkGPSGeolocationProvider>
GonkGPSGeolocationProvider::GetSingleton()
{
MOZ_ASSERT(NS_IsMainThread());
if (!sSingleton)
sSingleton = new GonkGPSGeolocationProvider();
RefPtr<GonkGPSGeolocationProvider> provider = sSingleton;
return provider.forget();
}
const GpsInterface*
GonkGPSGeolocationProvider::GetGPSInterface()
{
hw_module_t* module;
if (hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module))
return nullptr;
hw_device_t* device;
if (module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device))
return nullptr;
gps_device_t* gps_device = (gps_device_t *)device;
const GpsInterface* result = gps_device->get_gps_interface(gps_device);
if (result->size != sizeof(GpsInterface)) {
return nullptr;
}
return result;
}
void
GonkGPSGeolocationProvider::RequestSettingValue(const char* aKey)
{
MOZ_ASSERT(aKey);
nsCOMPtr<nsISettingsService> ss = do_GetService("@mozilla.org/settingsService;1");
if (!ss) {
MOZ_ASSERT(ss);
return;
}
nsCOMPtr<nsISettingsServiceLock> lock;
nsresult rv = ss->CreateLock(nullptr, getter_AddRefs(lock));
if (NS_FAILED(rv)) {
ERR("error while createLock setting '%s': %d\n", aKey, uint32_t(rv));
return;
}
rv = lock->Get(aKey, this);
if (NS_FAILED(rv)) {
ERR("error while get setting '%s': %d\n", aKey, uint32_t(rv));
return;
}
}
void
GonkGPSGeolocationProvider::InjectLocation(double latitude,
double longitude,
float accuracy)
{
if (gDebug_isLoggingEnabled) {
DBG("injecting location (%f, %f) accuracy: %f", latitude, longitude, accuracy);
}
MOZ_ASSERT(NS_IsMainThread());
if (!mGpsInterface) {
return;
}
mGpsInterface->inject_location(latitude, longitude, accuracy);
}
void
GonkGPSGeolocationProvider::Init()
{
// Must not be main thread. Some GPS driver's first init takes very long.
MOZ_ASSERT(!NS_IsMainThread());
mGpsInterface = GetGPSInterface();
if (!mGpsInterface) {
return;
}
if (!mCallbacks.size) {
mCallbacks.size = sizeof(GpsCallbacks);
mCallbacks.location_cb = LocationCallback;
mCallbacks.status_cb = StatusCallback;
mCallbacks.sv_status_cb = SvStatusCallback;
mCallbacks.nmea_cb = NmeaCallback;
mCallbacks.set_capabilities_cb = SetCapabilitiesCallback;
mCallbacks.acquire_wakelock_cb = AcquireWakelockCallback;
mCallbacks.release_wakelock_cb = ReleaseWakelockCallback;
mCallbacks.create_thread_cb = CreateThreadCallback;
#ifdef GPS_CAPABILITY_ON_DEMAND_TIME
mCallbacks.request_utc_time_cb = RequestUtcTimeCallback;
#endif
}
if (mGpsInterface->init(&mCallbacks) != 0) {
return;
}
NS_DispatchToMainThread(NewRunnableMethod(this, &GonkGPSGeolocationProvider::StartGPS));
}
void
GonkGPSGeolocationProvider::StartGPS()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mGpsInterface);
int32_t update = Preferences::GetInt("geo.default.update", kDefaultPeriod);
int positionMode = GPS_POSITION_MODE_STANDALONE;
if (!mSupportsScheduling) {
update = kDefaultPeriod;
}
mGpsInterface->set_position_mode(positionMode,
GPS_POSITION_RECURRENCE_PERIODIC,
update, 0, 0);
#if FLUSH_AIDE_DATA
// Delete cached data
mGpsInterface->delete_aiding_data(GPS_DELETE_ALL);
#endif
mGpsInterface->start();
}
NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider::NetworkLocationUpdate,
nsIGeolocationUpdate)
NS_IMETHODIMP
GonkGPSGeolocationProvider::NetworkLocationUpdate::Update(nsIDOMGeoPosition *position)
{
RefPtr<GonkGPSGeolocationProvider> provider =
GonkGPSGeolocationProvider::GetSingleton();
nsCOMPtr<nsIDOMGeoPositionCoords> coords;
position->GetCoords(getter_AddRefs(coords));
if (!coords) {
return NS_ERROR_FAILURE;
}
double lat, lon, acc;
coords->GetLatitude(&lat);
coords->GetLongitude(&lon);
coords->GetAccuracy(&acc);
double delta = -1.0;
static double sLastMLSPosLat = 0;
static double sLastMLSPosLon = 0;
if (0 != sLastMLSPosLon || 0 != sLastMLSPosLat) {
delta = CalculateDeltaInMeter(lat, lon, sLastMLSPosLat, sLastMLSPosLon);
}
sLastMLSPosLat = lat;
sLastMLSPosLon = lon;
// if the MLS coord change is smaller than this arbitrarily small value
// assume the MLS coord is unchanged, and stick with the GPS location
const double kMinMLSCoordChangeInMeters = 10;
DOMTimeStamp time_ms = 0;
if (provider->mLastGPSPosition) {
provider->mLastGPSPosition->GetTimestamp(&time_ms);
}
const int64_t diff_ms = (PR_Now() / PR_USEC_PER_MSEC) - time_ms;
// We want to distinguish between the GPS being inactive completely
// and temporarily inactive. In the former case, we would use a low
// accuracy network location; in the latter, we only want a network
// location that appears to updating with movement.
const bool isGPSFullyInactive = diff_ms > 1000 * 60 * 2; // two mins
const bool isGPSTempInactive = diff_ms > 1000 * 10; // 10 secs
if (provider->mLocationCallback) {
if (isGPSFullyInactive ||
(isGPSTempInactive && delta > kMinMLSCoordChangeInMeters))
{
if (gDebug_isLoggingEnabled) {
DBG("Using MLS, GPS age:%fs, MLS Delta:%fm\n", diff_ms / 1000.0, delta);
}
provider->mLocationCallback->Update(position);
} else if (provider->mLastGPSPosition) {
if (gDebug_isLoggingEnabled) {
DBG("Using old GPS age:%fs\n", diff_ms / 1000.0);
}
// This is a fallback case so that the GPS provider responds with its last
// location rather than waiting for a more recent GPS or network location.
// The service decides if the location is too old, not the provider.
provider->mLocationCallback->Update(provider->mLastGPSPosition);
}
}
provider->InjectLocation(lat, lon, acc);
return NS_OK;
}
NS_IMETHODIMP
GonkGPSGeolocationProvider::NetworkLocationUpdate::NotifyError(uint16_t error)
{
return NS_OK;
}
NS_IMETHODIMP
GonkGPSGeolocationProvider::Startup()
{
MOZ_ASSERT(NS_IsMainThread());
if (mStarted) {
return NS_OK;
}
RequestSettingValue(kSettingDebugEnabled);
RequestSettingValue(kSettingDebugGpsIgnored);
// Setup an observer to watch changes to the setting.
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
MOZ_ASSERT(!mObservingSettingsChange);
nsresult rv = observerService->AddObserver(this, kMozSettingsChangedTopic, false);
if (NS_FAILED(rv)) {
NS_WARNING("geo: Gonk GPS AddObserver failed");
} else {
mObservingSettingsChange = true;
}
}
if (!mInitThread) {
nsresult rv = NS_NewNamedThread("Gonk GPS", getter_AddRefs(mInitThread));
NS_ENSURE_SUCCESS(rv, rv);
}
mInitThread->Dispatch(NewRunnableMethod(this, &GonkGPSGeolocationProvider::Init),
NS_DISPATCH_NORMAL);
mNetworkLocationProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1");
if (mNetworkLocationProvider) {
nsresult rv = mNetworkLocationProvider->Startup();
if (NS_SUCCEEDED(rv)) {
RefPtr<NetworkLocationUpdate> update = new NetworkLocationUpdate();
mNetworkLocationProvider->Watch(update);
}
}
mStarted = true;
return NS_OK;
}
NS_IMETHODIMP
GonkGPSGeolocationProvider::Watch(nsIGeolocationUpdate* aCallback)
{
MOZ_ASSERT(NS_IsMainThread());
mLocationCallback = aCallback;
return NS_OK;
}
NS_IMETHODIMP
GonkGPSGeolocationProvider::Shutdown()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mStarted) {
return NS_OK;
}
mStarted = false;
if (mNetworkLocationProvider) {
mNetworkLocationProvider->Shutdown();
mNetworkLocationProvider = nullptr;
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
nsresult rv;
rv = obs->RemoveObserver(this, kMozSettingsChangedTopic);
if (NS_FAILED(rv)) {
NS_WARNING("geo: Gonk GPS mozsettings RemoveObserver failed");
} else {
mObservingSettingsChange = false;
}
}
mInitThread->Dispatch(NewRunnableMethod(this, &GonkGPSGeolocationProvider::ShutdownGPS),
NS_DISPATCH_NORMAL);
return NS_OK;
}
void
GonkGPSGeolocationProvider::ShutdownGPS()
{
MOZ_ASSERT(!mStarted, "Should only be called after Shutdown");
if (mGpsInterface) {
mGpsInterface->stop();
mGpsInterface->cleanup();
}
}
NS_IMETHODIMP
GonkGPSGeolocationProvider::SetHighAccuracy(bool)
{
return NS_OK;
}
namespace {
int
ConvertToGpsNetworkType(int aNetworkInterfaceType)
{
switch (aNetworkInterfaceType) {
case nsINetworkInfo::NETWORK_TYPE_WIFI:
return AGPS_RIL_NETWORK_TYPE_WIFI;
case nsINetworkInfo::NETWORK_TYPE_MOBILE:
return AGPS_RIL_NETWORK_TYPE_MOBILE;
case nsINetworkInfo::NETWORK_TYPE_MOBILE_MMS:
return AGPS_RIL_NETWORK_TYPE_MOBILE_MMS;
case nsINetworkInfo::NETWORK_TYPE_MOBILE_SUPL:
return AGPS_RIL_NETWORK_TYPE_MOBILE_SUPL;
case nsINetworkInfo::NETWORK_TYPE_MOBILE_DUN:
return AGPS_RIL_NETWORK_TTYPE_MOBILE_DUN;
default:
NS_WARNING(nsPrintfCString("Unknown network type mapping %d",
aNetworkInterfaceType).get());
return -1;
}
}
} // namespace
NS_IMETHODIMP
GonkGPSGeolocationProvider::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(NS_IsMainThread());
if (!strcmp(aTopic, kMozSettingsChangedTopic)) {
// Read changed setting value
RootedDictionary<SettingChangeNotification> setting(RootingCx());
if (!WrappedJSToDictionary(aSubject, setting)) {
return NS_OK;
}
if (setting.mKey.EqualsASCII(kSettingDebugGpsIgnored)) {
LOG("received mozsettings-changed: ignoring\n");
gDebug_isGPSLocationIgnored =
setting.mValue.isBoolean() ? setting.mValue.toBoolean() : false;
if (gDebug_isLoggingEnabled) {
DBG("GPS ignored %d\n", gDebug_isGPSLocationIgnored);
}
return NS_OK;
} else if (setting.mKey.EqualsASCII(kSettingDebugEnabled)) {
LOG("received mozsettings-changed: logging\n");
gDebug_isLoggingEnabled =
setting.mValue.isBoolean() ? setting.mValue.toBoolean() : false;
return NS_OK;
}
}
return NS_OK;
}
/** nsISettingsServiceCallback **/
NS_IMETHODIMP
GonkGPSGeolocationProvider::Handle(const nsAString& aName,
JS::Handle<JS::Value> aResult)
{
return NS_OK;
}
NS_IMETHODIMP
GonkGPSGeolocationProvider::HandleError(const nsAString& aErrorMessage)
{
return NS_OK;
}

Просмотреть файл

@ -1,103 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
*
* 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.
*/
#ifndef GonkGPSGeolocationProvider_h
#define GonkGPSGeolocationProvider_h
#include <hardware/gps.h> // for GpsInterface
#include "nsCOMPtr.h"
#include "nsIGeolocationProvider.h"
#include "nsIObserver.h"
#include "nsIDOMGeoPosition.h"
#include "nsISettingsService.h"
class nsIThread;
#define GONK_GPS_GEOLOCATION_PROVIDER_CID \
{ 0x48525ec5, 0x5a7f, 0x490a, { 0x92, 0x77, 0xba, 0x66, 0xe0, 0xd2, 0x2c, 0x8b } }
#define GONK_GPS_GEOLOCATION_PROVIDER_CONTRACTID \
"@mozilla.org/gonk-gps-geolocation-provider;1"
class GonkGPSGeolocationProvider : public nsIGeolocationProvider
, public nsIObserver
, public nsISettingsServiceCallback
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIGEOLOCATIONPROVIDER
NS_DECL_NSIOBSERVER
NS_DECL_NSISETTINGSSERVICECALLBACK
static already_AddRefed<GonkGPSGeolocationProvider> GetSingleton();
private:
/* Client should use GetSingleton() to get the provider instance. */
GonkGPSGeolocationProvider();
GonkGPSGeolocationProvider(const GonkGPSGeolocationProvider &);
GonkGPSGeolocationProvider & operator = (const GonkGPSGeolocationProvider &);
virtual ~GonkGPSGeolocationProvider();
static void LocationCallback(GpsLocation* location);
static void StatusCallback(GpsStatus* status);
static void SvStatusCallback(GpsSvStatus* sv_info);
static void NmeaCallback(GpsUtcTime timestamp, const char* nmea, int length);
static void SetCapabilitiesCallback(uint32_t capabilities);
static void AcquireWakelockCallback();
static void ReleaseWakelockCallback();
static pthread_t CreateThreadCallback(const char* name, void (*start)(void*), void* arg);
static void RequestUtcTimeCallback();
static GpsCallbacks mCallbacks;
void Init();
void StartGPS();
void ShutdownGPS();
void InjectLocation(double latitude, double longitude, float accuracy);
void RequestSettingValue(const char* aKey);
const GpsInterface* GetGPSInterface();
static GonkGPSGeolocationProvider* sSingleton;
bool mStarted;
bool mSupportsScheduling;
bool mObservingSettingsChange;
bool mSupportsSingleShot;
bool mSupportsTimeInjection;
const GpsInterface* mGpsInterface;
nsCOMPtr<nsIGeolocationUpdate> mLocationCallback;
nsCOMPtr<nsIThread> mInitThread;
nsCOMPtr<nsIGeolocationProvider> mNetworkLocationProvider;
nsCOMPtr<nsIDOMGeoPosition> mLastGPSPosition;
class NetworkLocationUpdate : public nsIGeolocationUpdate
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIGEOLOCATIONUPDATE
NetworkLocationUpdate() {}
private:
virtual ~NetworkLocationUpdate() {}
};
};
#endif /* GonkGPSGeolocationProvider_h */

Просмотреть файл

@ -1,56 +0,0 @@
/* -*- 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_mozmtpcommon_h__
#define mozilla_system_mozmtpcommon_h__
#include "mozilla/Types.h"
#include <android/log.h>
#define USE_DEBUG 0
#if USE_DEBUG
#define MTP_DBG(msg, ...) \
__android_log_print(ANDROID_LOG_DEBUG, "MozMtp", \
"%s: " msg, __FUNCTION__, ##__VA_ARGS__)
#else
#define MTP_DBG(msg, ...)
#endif
#define MTP_LOG(msg, ...) \
__android_log_print(ANDROID_LOG_INFO, "MozMtp", \
"%s: " msg, __FUNCTION__, ##__VA_ARGS__)
#define MTP_ERR(msg, ...) \
__android_log_print(ANDROID_LOG_ERROR, "MozMtp", \
"%s: " msg, __FUNCTION__, ##__VA_ARGS__)
#define BEGIN_MTP_NAMESPACE \
namespace mozilla { namespace system { namespace mtp {
#define END_MTP_NAMESPACE \
} /* namespace mtp */ } /* namespace system */ } /* namespace mozilla */
#define USING_MTP_NAMESPACE \
using namespace mozilla::system::mtp;
namespace android {
class MOZ_EXPORT MtpServer;
class MOZ_EXPORT MtpStorage;
class MOZ_EXPORT MtpStringBuffer;
class MOZ_EXPORT MtpDatabase;
class MOZ_EXPORT MtpDataPacket;
class MOZ_EXPORT MtpProperty;
}
#include <mtp.h>
#include <MtpDatabase.h>
#include <MtpObjectInfo.h>
#include <MtpProperty.h>
#include <MtpServer.h>
#include <MtpStorage.h>
#include <MtpStringBuffer.h>
#include <MtpTypes.h>
#endif // mozilla_system_mtpcommon_h__

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,288 +0,0 @@
/* -*- 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__

Просмотреть файл

@ -1,263 +0,0 @@
/* -*- 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/. */
#include "MozMtpServer.h"
#include "MozMtpDatabase.h"
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <cutils/properties.h>
#include <private/android_filesystem_config.h>
#include "base/message_loop.h"
#include "DeviceStorage.h"
#include "mozilla/LazyIdleThread.h"
#include "mozilla/Scoped.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsISupportsImpl.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
#include "Volume.h"
#define DEFAULT_THREAD_TIMEOUT_MS 30000
using namespace android;
using namespace mozilla;
BEGIN_MTP_NAMESPACE
static const char* kMtpWatcherUpdate = "mtp-watcher-update";
class MtpWatcherUpdateRunnable final : public Runnable
{
public:
MtpWatcherUpdateRunnable(MozMtpDatabase* aMozMtpDatabase,
RefCountedMtpServer* aMtpServer,
DeviceStorageFile* aFile,
const nsACString& aEventType)
: mMozMtpDatabase(aMozMtpDatabase),
mMtpServer(aMtpServer),
mFile(aFile),
mEventType(aEventType)
{}
NS_IMETHOD Run() override
{
// Runs on the MtpWatcherUpdate->mIOThread
MOZ_ASSERT(!NS_IsMainThread());
mMozMtpDatabase->MtpWatcherUpdate(mMtpServer, mFile, mEventType);
return NS_OK;
}
private:
RefPtr<MozMtpDatabase> mMozMtpDatabase;
RefPtr<RefCountedMtpServer> mMtpServer;
RefPtr<DeviceStorageFile> mFile;
nsCString mEventType;
};
// The MtpWatcherUpdate class listens for mtp-watcher-update events
// and tells the MtpServer about changes made in device storage.
class MtpWatcherUpdate final : public nsIObserver
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
MtpWatcherUpdate(MozMtpServer* aMozMtpServer)
: mMozMtpServer(aMozMtpServer)
{
MOZ_ASSERT(NS_IsMainThread());
mIOThread = new LazyIdleThread(
DEFAULT_THREAD_TIMEOUT_MS,
NS_LITERAL_CSTRING("MtpWatcherUpdate"));
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->AddObserver(this, kMtpWatcherUpdate, false);
}
NS_IMETHOD
Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
{
MOZ_ASSERT(NS_IsMainThread());
if (strcmp(aTopic, kMtpWatcherUpdate)) {
// We're only interested in mtp-watcher-update events
return NS_OK;
}
NS_ConvertUTF16toUTF8 eventType(aData);
if (!eventType.EqualsLiteral("modified") && !eventType.EqualsLiteral("deleted")) {
// Bug 1074604: Needn't handle "created" event, once file operation
// finished, it would trigger "modified" event.
return NS_OK;
}
DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject);
file->Dump(kMtpWatcherUpdate);
MTP_LOG("%s: file %s %s", kMtpWatcherUpdate,
NS_LossyConvertUTF16toASCII(file->mPath).get(),
eventType.get());
RefPtr<MozMtpDatabase> mozMtpDatabase = mMozMtpServer->GetMozMtpDatabase();
RefPtr<RefCountedMtpServer> mtpServer = mMozMtpServer->GetMtpServer();
// We're not supposed to perform I/O on the main thread, so punt the
// notification (which will write to /dev/mtp_usb) to an I/O Thread.
RefPtr<MtpWatcherUpdateRunnable> r =
new MtpWatcherUpdateRunnable(mozMtpDatabase, mtpServer, file, eventType);
mIOThread->Dispatch(r, NS_DISPATCH_NORMAL);
return NS_OK;
}
protected:
~MtpWatcherUpdate()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->RemoveObserver(this, kMtpWatcherUpdate);
}
private:
RefPtr<MozMtpServer> mMozMtpServer;
nsCOMPtr<nsIThread> mIOThread;
};
NS_IMPL_ISUPPORTS(MtpWatcherUpdate, nsIObserver)
static StaticRefPtr<MtpWatcherUpdate> sMtpWatcherUpdate;
class AllocMtpWatcherUpdateRunnable final : public Runnable
{
public:
AllocMtpWatcherUpdateRunnable(MozMtpServer* aMozMtpServer)
: mMozMtpServer(aMozMtpServer)
{}
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
sMtpWatcherUpdate = new MtpWatcherUpdate(mMozMtpServer);
return NS_OK;
}
private:
RefPtr<MozMtpServer> mMozMtpServer;
};
class FreeMtpWatcherUpdateRunnable final : public Runnable
{
public:
FreeMtpWatcherUpdateRunnable(MozMtpServer* aMozMtpServer)
: mMozMtpServer(aMozMtpServer)
{}
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
sMtpWatcherUpdate = nullptr;
return NS_OK;
}
private:
RefPtr<MozMtpServer> mMozMtpServer;
};
class MtpServerRunnable : public Runnable
{
public:
MtpServerRunnable(int aMtpUsbFd, MozMtpServer* aMozMtpServer)
: mMozMtpServer(aMozMtpServer),
mMtpUsbFd(aMtpUsbFd)
{
}
nsresult Run()
{
RefPtr<RefCountedMtpServer> server = mMozMtpServer->GetMtpServer();
DebugOnly<nsresult> rv =
NS_DispatchToMainThread(new AllocMtpWatcherUpdateRunnable(mMozMtpServer));
MOZ_ASSERT(NS_SUCCEEDED(rv));
MTP_LOG("MozMtpServer started");
server->run();
MTP_LOG("MozMtpServer finished");
// server->run will have closed the file descriptor.
mMtpUsbFd.forget();
rv = NS_DispatchToMainThread(new FreeMtpWatcherUpdateRunnable(mMozMtpServer));
MOZ_ASSERT(NS_SUCCEEDED(rv));
return NS_OK;
}
private:
RefPtr<MozMtpServer> mMozMtpServer;
ScopedClose mMtpUsbFd; // We want to hold this open while the server runs
};
already_AddRefed<RefCountedMtpServer>
MozMtpServer::GetMtpServer()
{
RefPtr<RefCountedMtpServer> server = mMtpServer;
return server.forget();
}
already_AddRefed<MozMtpDatabase>
MozMtpServer::GetMozMtpDatabase()
{
RefPtr<MozMtpDatabase> db = mMozMtpDatabase;
return db.forget();
}
bool
MozMtpServer::Init()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
const char *mtpUsbFilename = "/dev/mtp_usb";
mMtpUsbFd = open(mtpUsbFilename, O_RDWR);
if (mMtpUsbFd.get() < 0) {
MTP_ERR("open of '%s' failed((%s))", mtpUsbFilename, strerror(errno));
return false;
}
MTP_LOG("Opened '%s' fd %d", mtpUsbFilename, mMtpUsbFd.get());
mMozMtpDatabase = new MozMtpDatabase();
mMtpServer = new RefCountedMtpServer(mMtpUsbFd.get(), // fd
mMozMtpDatabase.get(), // MtpDatabase
false, // ptp?
AID_MEDIA_RW, // file group
0664, // file permissions
0775); // dir permissions
return true;
}
void
MozMtpServer::Run()
{
nsresult rv = NS_NewNamedThread("MtpServer", getter_AddRefs(mServerThread));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
MOZ_ASSERT(mServerThread);
mServerThread->Dispatch(new MtpServerRunnable(mMtpUsbFd.forget(), this), NS_DISPATCH_NORMAL);
}
END_MTP_NAMESPACE

Просмотреть файл

@ -1,61 +0,0 @@
/* -*- 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_mozmtpserver_h__
#define mozilla_system_mozmtpserver_h__
#include "MozMtpCommon.h"
#include "MozMtpDatabase.h"
#include "mozilla/FileUtils.h"
#include "nsCOMPtr.h"
#include "nsIThread.h"
BEGIN_MTP_NAMESPACE
using namespace android;
class RefCountedMtpServer : public MtpServer
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMtpServer)
RefCountedMtpServer(int aFd, MtpDatabase* aDatabase, bool aPtp,
int aFileGroup, int aFilePerm, int aDirectoryPerm)
: MtpServer(aFd, aDatabase, aPtp, aFileGroup, aFilePerm, aDirectoryPerm)
{
}
protected:
virtual ~RefCountedMtpServer() {}
};
class MozMtpServer
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpServer)
bool Init();
void Run();
already_AddRefed<RefCountedMtpServer> GetMtpServer();
already_AddRefed<MozMtpDatabase> GetMozMtpDatabase();
protected:
virtual ~MozMtpServer() {}
private:
RefPtr<RefCountedMtpServer> mMtpServer;
RefPtr<MozMtpDatabase> mMozMtpDatabase;
nsCOMPtr<nsIThread> mServerThread;
ScopedClose mMtpUsbFd;
};
END_MTP_NAMESPACE
#endif // mozilla_system_mozmtpserver_h__

Просмотреть файл

@ -1,135 +0,0 @@
/* -*- 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/. */
#include "MozMtpStorage.h"
#include "MozMtpDatabase.h"
#include "MozMtpServer.h"
#include "base/message_loop.h"
#include "nsXULAppAPI.h"
BEGIN_MTP_NAMESPACE
using namespace android;
MozMtpStorage::MozMtpStorage(Volume* aVolume, MozMtpServer* aMozMtpServer)
: mMozMtpServer(aMozMtpServer),
mVolume(aVolume)
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
// The MtpStorageID has the physical volume in the top 16 bits, and the
// logical volumein the lower 16 bits. We treat each volume as a separate
// phsyical storage;
mStorageID = mVolume->Id() << 16 | 1;
MTP_LOG("Storage constructed for Volume %s mStorageID 0x%08x",
aVolume->NameStr(), mStorageID);
Volume::RegisterVolumeObserver(this, "MozMtpStorage");
// Get things in sync
Notify(mVolume);
}
MozMtpStorage::~MozMtpStorage()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
MTP_LOG("Storage destructed for Volume %s mStorageID 0x%08x",
mVolume->NameStr(), mStorageID);
Volume::UnregisterVolumeObserver(this, "MozMtpStorage");
if (mMtpStorage) {
StorageUnavailable();
}
}
// virtual
void
MozMtpStorage::Notify(Volume* const& aVolume)
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
if (aVolume != mVolume) {
// Not our volume
return;
}
Volume::STATE volState = aVolume->State();
MTP_LOG("Volume %s mStorageID 0x%08x state changed to %s SharingEnabled: %d",
aVolume->NameStr(), mStorageID, aVolume->StateStr(),
aVolume->IsSharingEnabled());
// vol->IsSharingEnabled really only applies to UMS volumes. We assume that
// that as long as MTP is enabled, then all volumes will be shared. The UI
// currently doesn't give us anything more granular than on/off.
if (mMtpStorage) {
if (volState != nsIVolume::STATE_MOUNTED) {
// The volume is no longer accessible. We need to remove this storage
// from the MTP server
StorageUnavailable();
}
} else {
if (volState == nsIVolume::STATE_MOUNTED) {
// The volume is accessible. Tell the MTP server.
StorageAvailable();
}
}
}
void
MozMtpStorage::StorageAvailable()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
nsCString mountPoint = mVolume->MountPoint();
MTP_LOG("Adding Volume %s mStorageID 0x%08x mountPoint %s to MozMtpDatabase",
mVolume->NameStr(), mStorageID, mountPoint.get());
RefPtr<MozMtpDatabase> db = mMozMtpServer->GetMozMtpDatabase();
db->AddStorage(mStorageID, mountPoint.get(), mVolume->NameStr());
MOZ_ASSERT(!mMtpStorage);
//TODO: Figure out what to do about maxFileSize.
mMtpStorage.reset(new MtpStorage(mStorageID, // id
mountPoint.get(), // filePath
mVolume->NameStr(), // description
1024uLL * 1024uLL, // reserveSpace
mVolume->IsHotSwappable(), // removable
2uLL * 1024uLL * 1024uLL * 1024uLL)); // maxFileSize
RefPtr<RefCountedMtpServer> server = mMozMtpServer->GetMtpServer();
MTP_LOG("Adding Volume %s mStorageID 0x%08x mountPoint %s to MtpServer",
mVolume->NameStr(), mStorageID, mountPoint.get());
server->addStorage(mMtpStorage.get());
}
void
MozMtpStorage::StorageUnavailable()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
MOZ_ASSERT(mMtpStorage);
MTP_LOG("Removing mStorageID 0x%08x from MtpServer", mStorageID);
RefPtr<RefCountedMtpServer> server = mMozMtpServer->GetMtpServer();
server->removeStorage(mMtpStorage.get());
MTP_LOG("Removing mStorageID 0x%08x from MozMtpDatabse", mStorageID);
RefPtr<MozMtpDatabase> db = mMozMtpServer->GetMozMtpDatabase();
db->RemoveStorage(mStorageID);
mMtpStorage = nullptr;
}
END_MTP_NAMESPACE

Просмотреть файл

@ -1,47 +0,0 @@
/* -*- 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_mozmtpstorage_h__
#define mozilla_system_mozmtpstorage_h__
#include "MozMtpCommon.h"
#include "mozilla/UniquePtr.h"
#include "Volume.h"
BEGIN_MTP_NAMESPACE
using namespace android;
class MozMtpServer;
class MozMtpStorage : public Volume::EventObserver
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpStorage)
MozMtpStorage(Volume* aVolume, MozMtpServer* aMozMtpServer);
typedef nsTArray<RefPtr<MozMtpStorage> > Array;
private:
virtual ~MozMtpStorage();
virtual void Notify(Volume* const& aEvent);
void StorageAvailable();
void StorageUnavailable();
RefPtr<MozMtpServer> mMozMtpServer;
UniquePtr<MtpStorage> mMtpStorage;
RefPtr<Volume> mVolume;
MtpStorageID mStorageID;
};
END_MTP_NAMESPACE
#endif // mozilla_system_mozmtpstorage_h__

Просмотреть файл

@ -1,68 +0,0 @@
/* 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/. */
#include "NetIdManager.h"
NetIdManager::NetIdManager()
: mNextNetId(MIN_NET_ID)
{
}
int NetIdManager::getNextNetId()
{
// Modified from
// http://androidxref.com/5.0.0_r2/xref/frameworks/base/services/
// core/java/com/android/server/ConnectivityService.java#764
int netId = mNextNetId;
if (++mNextNetId > MAX_NET_ID) {
mNextNetId = MIN_NET_ID;
}
return netId;
}
void NetIdManager::acquire(const nsString& aInterfaceName,
NetIdInfo* aNetIdInfo)
{
// Lookup or create one.
if (!mInterfaceToNetIdHash.Get(aInterfaceName, aNetIdInfo)) {
aNetIdInfo->mNetId = getNextNetId();
aNetIdInfo->mRefCnt = 1;
} else {
aNetIdInfo->mRefCnt++;
}
// Update hash and return.
mInterfaceToNetIdHash.Put(aInterfaceName, *aNetIdInfo);
return;
}
bool NetIdManager::lookup(const nsString& aInterfaceName,
NetIdInfo* aNetIdInfo)
{
return mInterfaceToNetIdHash.Get(aInterfaceName, aNetIdInfo);
}
bool NetIdManager::release(const nsString& aInterfaceName,
NetIdInfo* aNetIdInfo)
{
if (!mInterfaceToNetIdHash.Get(aInterfaceName, aNetIdInfo)) {
return false; // No such key.
}
aNetIdInfo->mRefCnt--;
// Update the hash if still be referenced.
if (aNetIdInfo->mRefCnt > 0) {
mInterfaceToNetIdHash.Put(aInterfaceName, *aNetIdInfo);
return true;
}
// No longer be referenced. Remove the entry.
mInterfaceToNetIdHash.Remove(aInterfaceName);
return true;
}

Просмотреть файл

@ -1,45 +0,0 @@
/* 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 NetIdManager_h
#define NetIdManager_h
#include "nsString.h"
#include "nsDataHashtable.h"
// NetId is a logical network identifier defined by netd.
// A network is typically a physical one (i.e. PhysicalNetwork.cpp)
// for netd but it could be a virtual network as well.
// We currently use physical network only and use one-to-one
// network-interface mapping.
class NetIdManager {
public:
// keep in sync with system/netd/NetworkController.cpp
enum {
MIN_NET_ID = 100,
MAX_NET_ID = 65535,
};
// We need to count the number of references since different
// application like data and mms may use the same interface.
struct NetIdInfo {
int mNetId;
int mRefCnt;
};
public:
NetIdManager();
bool lookup(const nsString& aInterfaceName, NetIdInfo* aNetIdInfo);
void acquire(const nsString& aInterfaceName, NetIdInfo* aNetIdInfo);
bool release(const nsString& aInterfaceName, NetIdInfo* aNetIdInfo);
private:
int getNextNetId();
int mNextNetId;
nsDataHashtable<nsStringHashKey, NetIdInfo> mInterfaceToNetIdHash;
};
#endif

Просмотреть файл

@ -1,110 +0,0 @@
/* 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/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const NETWORKLISTSERVICE_CONTRACTID =
"@mozilla.org/network/interface-list-service;1";
const NETWORKLISTSERVICE_CID =
Components.ID("{3780be6e-7012-4e53-ade6-15212fb88a0d}");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsISyncMessageSender");
function NetworkInterfaceListService () {
}
NetworkInterfaceListService.prototype = {
classID: NETWORKLISTSERVICE_CID,
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterfaceListService]),
getDataInterfaceList: function(aConditions) {
return new NetworkInterfaceList(
cpmm.sendSyncMessage(
'NetworkInterfaceList:ListInterface',
{
excludeSupl: (aConditions &
Ci.nsINetworkInterfaceListService.
LIST_NOT_INCLUDE_SUPL_INTERFACES) != 0,
excludeMms: (aConditions &
Ci.nsINetworkInterfaceListService.
LIST_NOT_INCLUDE_MMS_INTERFACES) != 0,
excludeIms: (aConditions &
Ci.nsINetworkInterfaceListService.
LIST_NOT_INCLUDE_IMS_INTERFACES) != 0,
excludeDun: (aConditions &
Ci.nsINetworkInterfaceListService.
LIST_NOT_INCLUDE_DUN_INTERFACES) != 0,
excludeFota: (aConditions &
Ci.nsINetworkInterfaceListService.
LIST_NOT_INCLUDE_FOTA_INTERFACES) != 0
}
)[0]);
}
};
function FakeNetworkInfo(aAttributes) {
this.state = aAttributes.state;
this.type = aAttributes.type;
this.name = aAttributes.name;
this.ips = aAttributes.ips;
this.prefixLengths = aAttributes.prefixLengths;
this.gateways = aAttributes.gateways;
this.dnses = aAttributes.dnses;
}
FakeNetworkInfo.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInfo]),
getAddresses: function (ips, prefixLengths) {
ips.value = this.ips.slice();
prefixLengths.value = this.prefixLengths.slice();
return this.ips.length;
},
getGateways: function (count) {
if (count) {
count.value = this.gateways.length;
}
return this.gateways.slice();
},
getDnses: function (count) {
if (count) {
count.value = this.dnses.length;
}
return this.dnses.slice();
}
};
function NetworkInterfaceList (aInterfaceLiterals) {
this._interfaces = [];
for (let entry of aInterfaceLiterals) {
this._interfaces.push(new FakeNetworkInfo(entry));
}
}
NetworkInterfaceList.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterfaceList]),
getNumberOfInterface: function() {
return this._interfaces.length;
},
getInterfaceInfo: function(index) {
if (!this._interfaces) {
return null;
}
return this._interfaces[index];
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkInterfaceListService]);

Просмотреть файл

@ -1,17 +0,0 @@
# Copyright 2012 Mozilla Foundation and Mozilla contributors
#
# 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.
# NetworkInterfaceListService.js
component {3780be6e-7012-4e53-ade6-15212fb88a0d} NetworkInterfaceListService.js
contract @mozilla.org/network/interface-list-service;1 {3780be6e-7012-4e53-ade6-15212fb88a0d}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,3 +0,0 @@
# NetworkManager.js
component {1ba9346b-53b5-4660-9dc6-58f0b258d0a6} NetworkManager.js
contract @mozilla.org/network/manager;1 {1ba9346b-53b5-4660-9dc6-58f0b258d0a6}

Просмотреть файл

@ -1,794 +0,0 @@
/* 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/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
const NETWORKSERVICE_CONTRACTID = "@mozilla.org/network/service;1";
const NETWORKSERVICE_CID = Components.ID("{48c13741-aec9-4a86-8962-432011708261}");
const TOPIC_PREF_CHANGED = "nsPref:changed";
const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown";
const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled";
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkWorker",
"@mozilla.org/network/worker;1",
"nsINetworkWorker");
// 1xx - Requested action is proceeding
const NETD_COMMAND_PROCEEDING = 100;
// 2xx - Requested action has been successfully completed
const NETD_COMMAND_OKAY = 200;
// 4xx - The command is accepted but the requested action didn't
// take place.
const NETD_COMMAND_FAIL = 400;
// 5xx - The command syntax or parameters error
const NETD_COMMAND_ERROR = 500;
// 6xx - Unsolicited broadcasts
const NETD_COMMAND_UNSOLICITED = 600;
const WIFI_CTRL_INTERFACE = "wl0.1";
var debug;
function updateDebug() {
let debugPref = false; // set default value here.
try {
debugPref = debugPref || Services.prefs.getBoolPref(PREF_NETWORK_DEBUG_ENABLED);
} catch (e) {}
if (debugPref) {
debug = function(s) {
dump("-*- NetworkService: " + s + "\n");
};
} else {
debug = function(s) {};
}
}
updateDebug();
function netdResponseType(aCode) {
return Math.floor(aCode / 100) * 100;
}
function isError(aCode) {
let type = netdResponseType(aCode);
return (type !== NETD_COMMAND_PROCEEDING && type !== NETD_COMMAND_OKAY);
}
function Task(aId, aParams, aSetupFunction) {
this.id = aId;
this.params = aParams;
this.setupFunction = aSetupFunction;
}
function NetworkWorkerRequestQueue(aNetworkService) {
this.networkService = aNetworkService;
this.tasks = [];
}
NetworkWorkerRequestQueue.prototype = {
runQueue: function() {
if (this.tasks.length === 0) {
return;
}
let task = this.tasks[0];
debug("run task id: " + task.id);
if (typeof task.setupFunction === 'function') {
// If setupFunction returns false, skip sending to Network Worker but call
// handleWorkerMessage() directly with task id, as if the response was
// returned from Network Worker.
if (!task.setupFunction()) {
this.networkService.handleWorkerMessage({id: task.id});
return;
}
}
gNetworkWorker.postMessage(task.params);
},
enqueue: function(aId, aParams, aSetupFunction) {
debug("enqueue id: " + aId);
this.tasks.push(new Task(aId, aParams, aSetupFunction));
if (this.tasks.length === 1) {
this.runQueue();
}
},
dequeue: function(aId) {
debug("dequeue id: " + aId);
if (!this.tasks.length || this.tasks[0].id != aId) {
debug("Id " + aId + " is not on top of the queue");
return;
}
this.tasks.shift();
if (this.tasks.length > 0) {
// Run queue on the next tick.
Services.tm.dispatchToMainThread(() => {
this.runQueue();
});
}
}
};
/**
* This component watches for network interfaces changing state and then
* adjusts routes etc. accordingly.
*/
function NetworkService() {
debug("Starting NetworkService.");
let self = this;
if (gNetworkWorker) {
let networkListener = {
onEvent: function(aEvent) {
self.handleWorkerMessage(aEvent);
}
};
gNetworkWorker.start(networkListener);
}
// Callbacks to invoke when a reply arrives from the net_worker.
this.controlCallbacks = Object.create(null);
this.addedRoutes = new Map();
this.netWorkerRequestQueue = new NetworkWorkerRequestQueue(this);
this.shutdown = false;
Services.prefs.addObserver(PREF_NETWORK_DEBUG_ENABLED, this);
Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN);
}
NetworkService.prototype = {
classID: NETWORKSERVICE_CID,
classInfo: XPCOMUtils.generateCI({classID: NETWORKSERVICE_CID,
contractID: NETWORKSERVICE_CONTRACTID,
classDescription: "Network Service",
interfaces: [Ci.nsINetworkService]}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkService,
Ci.nsIObserver]),
addedRoutes: null,
shutdown: false,
// nsIObserver
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case TOPIC_PREF_CHANGED:
if (aData === PREF_NETWORK_DEBUG_ENABLED) {
updateDebug();
}
break;
case TOPIC_XPCOM_SHUTDOWN:
debug("NetworkService shutdown");
this.shutdown = true;
if (gNetworkWorker) {
gNetworkWorker.shutdown();
gNetworkWorker = null;
}
Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
Services.prefs.removeObserver(PREF_NETWORK_DEBUG_ENABLED, this);
break;
}
},
// Helpers
idgen: 0,
controlMessage: function(aParams, aCallback, aSetupFunction) {
if (this.shutdown) {
return;
}
let id = this.idgen++;
aParams.id = id;
if (aCallback) {
this.controlCallbacks[id] = aCallback;
}
// For now, we use aSetupFunction to determine if this command needs to be
// queued or not.
if (aSetupFunction) {
this.netWorkerRequestQueue.enqueue(id, aParams, aSetupFunction);
return;
}
if (gNetworkWorker) {
gNetworkWorker.postMessage(aParams);
}
},
handleWorkerMessage: function(aResponse) {
debug("NetworkManager received message from worker: " + JSON.stringify(aResponse));
let id = aResponse.id;
if (aResponse.broadcast === true) {
Services.obs.notifyObservers(null, aResponse.topic, aResponse.reason);
return;
}
let callback = this.controlCallbacks[id];
if (callback) {
callback.call(this, aResponse);
delete this.controlCallbacks[id];
}
this.netWorkerRequestQueue.dequeue(id);
},
// nsINetworkService
_setNetworkTetheringAlarm(aEnable, aInterface, aThreshold, aCallback) {
debug("_setNetworkTetheringAlarm for tethering" + aEnable);
let cmd = aEnable ? "setTetheringAlarm" : "removeTetheringAlarm";
let params = {
cmd: cmd,
ifname: aInterface,
threshold: aThreshold,
};
this.controlMessage(params, function(aData) {
let code = aData.resultCode;
let reason = aData.resultReason;
let enableString = aEnable ? "Enable" : "Disable";
debug(enableString + " tethering Alarm result: Code " + code + " reason " + reason);
if (aCallback) {
aCallback.networkUsageAlarmResult(null);
}
});
},
setNetworkInterfaceAlarm: function(aInterfaceName, aThreshold, aCallback) {
if (!aInterfaceName) {
aCallback.networkUsageAlarmResult(-1);
return;
}
let self = this;
this._disableNetworkInterfaceAlarm(aInterfaceName, function(aResult) {
if (aThreshold < 0) {
if (!isError(aResult.resultCode)) {
aCallback.networkUsageAlarmResult(null);
return;
}
aCallback.networkUsageAlarmResult(aResult.reason);
return
}
// Check if tethering is enabled
let params = {
cmd: "getTetheringStatus"
};
self.controlMessage(params, function(aResult) {
if (isError(aResult.resultCode)) {
aCallback.networkUsageAlarmResult(aResult.reason);
return;
}
if (aResult.resultReason.indexOf('started') == -1) {
// Tethering disabled, set interfaceAlarm
self._setNetworkInterfaceAlarm(aInterfaceName, aThreshold, aCallback);
return;
}
// Tethering enabled, set globalAlarm
self._setNetworkTetheringAlarm(true, aInterfaceName, aThreshold, aCallback);
});
});
},
_setNetworkInterfaceAlarm: function(aInterfaceName, aThreshold, aCallback) {
debug("setNetworkInterfaceAlarm for " + aInterfaceName + " at " + aThreshold + "bytes");
let params = {
cmd: "setNetworkInterfaceAlarm",
ifname: aInterfaceName,
threshold: aThreshold
};
params.report = true;
this.controlMessage(params, function(aResult) {
if (!isError(aResult.resultCode)) {
aCallback.networkUsageAlarmResult(null);
return;
}
this._enableNetworkInterfaceAlarm(aInterfaceName, aThreshold, aCallback);
});
},
_enableNetworkInterfaceAlarm: function(aInterfaceName, aThreshold, aCallback) {
debug("enableNetworkInterfaceAlarm for " + aInterfaceName + " at " + aThreshold + "bytes");
let params = {
cmd: "enableNetworkInterfaceAlarm",
ifname: aInterfaceName,
threshold: aThreshold
};
params.report = true;
this.controlMessage(params, function(aResult) {
if (!isError(aResult.resultCode)) {
aCallback.networkUsageAlarmResult(null);
return;
}
aCallback.networkUsageAlarmResult(aResult.reason);
});
},
_disableNetworkInterfaceAlarm: function(aInterfaceName, aCallback) {
debug("disableNetworkInterfaceAlarm for " + aInterfaceName);
let params = {
cmd: "disableNetworkInterfaceAlarm",
ifname: aInterfaceName,
};
params.report = true;
this.controlMessage(params, function(aResult) {
aCallback(aResult);
});
},
setWifiOperationMode: function(aInterfaceName, aMode, aCallback) {
debug("setWifiOperationMode on " + aInterfaceName + " to " + aMode);
let params = {
cmd: "setWifiOperationMode",
ifname: aInterfaceName,
mode: aMode
};
params.report = true;
this.controlMessage(params, function(aResult) {
if (isError(aResult.resultCode)) {
aCallback.wifiOperationModeResult("netd command error");
} else {
aCallback.wifiOperationModeResult(null);
}
});
},
resetRoutingTable: function(aInterfaceName, aCallback) {
let options = {
cmd: "removeNetworkRoute",
ifname: aInterfaceName
};
this.controlMessage(options, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
},
setDNS: function(aInterfaceName, aDnsesCount, aDnses, aGatewaysCount,
aGateways, aCallback) {
debug("Going to set DNS to " + aInterfaceName);
let options = {
cmd: "setDNS",
ifname: aInterfaceName,
domain: "mozilla." + aInterfaceName + ".domain",
dnses: aDnses,
gateways: aGateways
};
this.controlMessage(options, function(aResult) {
aCallback.setDnsResult(aResult.success ? null : aResult.reason);
});
},
setDefaultRoute: function(aInterfaceName, aCount, aGateways, aCallback) {
debug("Going to change default route to " + aInterfaceName);
let options = {
cmd: "setDefaultRoute",
ifname: aInterfaceName,
gateways: aGateways
};
this.controlMessage(options, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
},
removeDefaultRoute: function(aInterfaceName, aCount, aGateways, aCallback) {
debug("Remove default route for " + aInterfaceName);
let options = {
cmd: "removeDefaultRoute",
ifname: aInterfaceName,
gateways: aGateways
};
this.controlMessage(options, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
},
_routeToString: function(aInterfaceName, aHost, aPrefixLength, aGateway) {
return aHost + "-" + aPrefixLength + "-" + aGateway + "-" + aInterfaceName;
},
modifyRoute: function(aAction, aInterfaceName, aHost, aPrefixLength, aGateway) {
let command;
switch (aAction) {
case Ci.nsINetworkService.MODIFY_ROUTE_ADD:
command = 'addHostRoute';
break;
case Ci.nsINetworkService.MODIFY_ROUTE_REMOVE:
command = 'removeHostRoute';
break;
default:
debug('Unknown action: ' + aAction);
return Promise.reject();
}
let route = this._routeToString(aInterfaceName, aHost, aPrefixLength, aGateway);
let setupFunc = () => {
let count = this.addedRoutes.get(route);
debug(command + ": " + route + " -> " + count);
// Return false if there is no need to send the command to network worker.
if ((aAction == Ci.nsINetworkService.MODIFY_ROUTE_ADD && count) ||
(aAction == Ci.nsINetworkService.MODIFY_ROUTE_REMOVE &&
(!count || count > 1))) {
return false;
}
return true;
};
debug(command + " " + aHost + " on " + aInterfaceName);
let options = {
cmd: command,
ifname: aInterfaceName,
gateway: aGateway,
prefixLength: aPrefixLength,
ip: aHost
};
return new Promise((aResolve, aReject) => {
this.controlMessage(options, (aData) => {
let count = this.addedRoutes.get(route);
// Remove route from addedRoutes on success or failure.
if (aAction == Ci.nsINetworkService.MODIFY_ROUTE_REMOVE) {
if (count > 1) {
this.addedRoutes.set(route, count - 1);
} else {
this.addedRoutes.delete(route);
}
}
if (aData.error) {
aReject(aData.reason);
return;
}
if (aAction == Ci.nsINetworkService.MODIFY_ROUTE_ADD) {
this.addedRoutes.set(route, count ? count + 1 : 1);
}
aResolve();
}, setupFunc);
});
},
addSecondaryRoute: function(aInterfaceName, aRoute, aCallback) {
debug("Going to add route to secondary table on " + aInterfaceName);
let options = {
cmd: "addSecondaryRoute",
ifname: aInterfaceName,
ip: aRoute.ip,
prefix: aRoute.prefix,
gateway: aRoute.gateway
};
this.controlMessage(options, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
},
removeSecondaryRoute: function(aInterfaceName, aRoute, aCallback) {
debug("Going to remove route from secondary table on " + aInterfaceName);
let options = {
cmd: "removeSecondaryRoute",
ifname: aInterfaceName,
ip: aRoute.ip,
prefix: aRoute.prefix,
gateway: aRoute.gateway
};
this.controlMessage(options, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
},
// Enable/Disable DHCP server.
setDhcpServer: function(aEnabled, aConfig, aCallback) {
if (null === aConfig) {
aConfig = {};
}
aConfig.cmd = "setDhcpServer";
aConfig.enabled = aEnabled;
this.controlMessage(aConfig, function(aResponse) {
if (!aResponse.success) {
aCallback.dhcpServerResult('Set DHCP server error');
return;
}
aCallback.dhcpServerResult(null);
});
},
// Enable/disable WiFi tethering by sending commands to netd.
setWifiTethering: function(aEnable, aConfig, aCallback) {
// config should've already contained:
// .ifname
// .internalIfname
// .externalIfname
aConfig.wifictrlinterfacename = WIFI_CTRL_INTERFACE;
aConfig.cmd = "setWifiTethering";
// The callback function in controlMessage may not be fired immediately.
this.controlMessage(aConfig, (aData) => {
let code = aData.resultCode;
let reason = aData.resultReason;
let enable = aData.enable;
let enableString = aEnable ? "Enable" : "Disable";
debug(enableString + " Wifi tethering result: Code " + code + " reason " + reason);
this.setNetworkTetheringAlarm(aEnable, aConfig.externalIfname);
if (isError(code)) {
aCallback.wifiTetheringEnabledChange("netd command error");
} else {
aCallback.wifiTetheringEnabledChange(null);
}
});
},
// Enable/disable USB tethering by sending commands to netd.
setUSBTethering: function(aEnable, aConfig, aCallback) {
aConfig.cmd = "setUSBTethering";
// The callback function in controlMessage may not be fired immediately.
this.controlMessage(aConfig, (aData) => {
let code = aData.resultCode;
let reason = aData.resultReason;
let enable = aData.enable;
let enableString = aEnable ? "Enable" : "Disable";
debug(enableString + " USB tethering result: Code " + code + " reason " + reason);
this.setNetworkTetheringAlarm(aEnable, aConfig.externalIfname);
if (isError(code)) {
aCallback.usbTetheringEnabledChange("netd command error");
} else {
aCallback.usbTetheringEnabledChange(null);
}
});
},
// Switch usb function by modifying property of persist.sys.usb.config.
enableUsbRndis: function(aEnable, aCallback) {
debug("enableUsbRndis: " + aEnable);
let params = {
cmd: "enableUsbRndis",
enable: aEnable
};
// Ask net work to report the result when this value is set to true.
if (aCallback) {
params.report = true;
} else {
params.report = false;
}
// The callback function in controlMessage may not be fired immediately.
//this._usbTetheringAction = TETHERING_STATE_ONGOING;
this.controlMessage(params, function(aData) {
aCallback.enableUsbRndisResult(aData.result, aData.enable);
});
},
updateUpStream: function(aPrevious, aCurrent, aCallback) {
let params = {
cmd: "updateUpStream",
preInternalIfname: aPrevious.internalIfname,
preExternalIfname: aPrevious.externalIfname,
curInternalIfname: aCurrent.internalIfname,
curExternalIfname: aCurrent.externalIfname
};
this.controlMessage(params, function(aData) {
let code = aData.resultCode;
let reason = aData.resultReason;
debug("updateUpStream result: Code " + code + " reason " + reason);
aCallback.updateUpStreamResult(!isError(code), aData.curExternalIfname);
});
},
getInterfaces: function(callback) {
let params = {
cmd: "getInterfaces",
isAsync: true
};
this.controlMessage(params, function(data) {
debug("getInterfaces result: " + JSON.stringify(data));
let success = !isError(data.resultCode);
callback.getInterfacesResult(success, data.interfaceList);
});
},
getInterfaceConfig: function(ifname, callback) {
let params = {
cmd: "getInterfaceConfig",
ifname: ifname,
isAsync: true
};
this.controlMessage(params, function(data) {
debug("getInterfaceConfig result: " + JSON.stringify(data));
let success = !isError(data.resultCode);
let result = { ip: data.ipAddr,
prefix: data.prefixLength,
link: data.flag,
mac: data.macAddr };
callback.getInterfaceConfigResult(success, result);
});
},
setInterfaceConfig: function(config, callback) {
config.cmd = "setInterfaceConfig";
config.isAsync = true;
this.controlMessage(config, function(data) {
debug("setInterfaceConfig result: " + JSON.stringify(data));
let success = !isError(data.resultCode);
callback.setInterfaceConfigResult(success);
});
},
configureInterface: function(aConfig, aCallback) {
let params = {
cmd: "configureInterface",
ifname: aConfig.ifname,
ipaddr: aConfig.ipaddr,
mask: aConfig.mask,
gateway_long: aConfig.gateway,
dns1_long: aConfig.dns1,
dns2_long: aConfig.dns2,
};
this.controlMessage(params, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
},
dhcpRequest: function(aInterfaceName, aCallback) {
let params = {
cmd: "dhcpRequest",
ifname: aInterfaceName
};
this.controlMessage(params, function(aResult) {
aCallback.dhcpRequestResult(!aResult.error, aResult.error ? null : aResult);
});
},
stopDhcp: function(aInterfaceName, aCallback) {
let params = {
cmd: "stopDhcp",
ifname: aInterfaceName
};
this.controlMessage(params, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
},
enableInterface: function(aInterfaceName, aCallback) {
let params = {
cmd: "enableInterface",
ifname: aInterfaceName
};
this.controlMessage(params, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
},
disableInterface: function(aInterfaceName, aCallback) {
let params = {
cmd: "disableInterface",
ifname: aInterfaceName
};
this.controlMessage(params, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
},
resetConnections: function(aInterfaceName, aCallback) {
let params = {
cmd: "resetConnections",
ifname: aInterfaceName
};
this.controlMessage(params, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
},
createNetwork: function(aInterfaceName, aCallback) {
let params = {
cmd: "createNetwork",
ifname: aInterfaceName
};
this.controlMessage(params, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
},
destroyNetwork: function(aInterfaceName, aCallback) {
let params = {
cmd: "destroyNetwork",
ifname: aInterfaceName
};
this.controlMessage(params, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
},
getNetId: function(aInterfaceName) {
let params = {
cmd: "getNetId",
ifname: aInterfaceName
};
return new Promise((aResolve, aReject) => {
this.controlMessage(params, result => {
if (result.error) {
aReject(result.reason);
return;
}
aResolve(result.netId);
});
});
},
setMtu: function (aInterfaceName, aMtu, aCallback) {
debug("Set MTU on " + aInterfaceName + ": " + aMtu);
let params = {
cmd: "setMtu",
ifname: aInterfaceName,
mtu: aMtu
};
this.controlMessage(params, function(aResult) {
aCallback.nativeCommandResult(!aResult.error);
});
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkService]);

Просмотреть файл

@ -1,3 +0,0 @@
# NetworkService.js
component {48c13741-aec9-4a86-8962-432011708261} NetworkService.js
contract @mozilla.org/network/service;1 {48c13741-aec9-4a86-8962-432011708261}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,498 +0,0 @@
/* 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 NetworkUtils_h
#define NetworkUtils_h
#include "nsAutoPtr.h"
#include "nsString.h"
#include "mozilla/dom/NetworkOptionsBinding.h"
#include "mozilla/dom/network/NetUtils.h"
#include "mozilla/ipc/Netd.h"
#include "nsTArray.h"
#include "NetIdManager.h"
class NetworkParams;
class CommandChain;
class CommandCallback {
public:
typedef void (*CallbackType)(CommandChain*, bool,
mozilla::dom::NetworkResultOptions& aResult);
typedef void (*CallbackWrapperType)(CallbackType aOriginalCallback,
CommandChain*, bool,
mozilla::dom::NetworkResultOptions& aResult);
CommandCallback()
: mCallback(nullptr)
, mCallbackWrapper(nullptr)
{
}
CommandCallback(CallbackType aCallback)
: mCallback(aCallback)
, mCallbackWrapper(nullptr)
{
}
CommandCallback(CallbackWrapperType aCallbackWrapper,
CommandCallback aOriginalCallback)
: mCallback(aOriginalCallback.mCallback)
, mCallbackWrapper(aCallbackWrapper)
{
}
void operator()(CommandChain* aChain, bool aError,
mozilla::dom::NetworkResultOptions& aResult)
{
if (mCallbackWrapper) {
return mCallbackWrapper(mCallback, aChain, aError, aResult);
}
if (mCallback) {
return mCallback(aChain, aError, aResult);
}
}
private:
CallbackType mCallback;
CallbackWrapperType mCallbackWrapper;
};
typedef void (*CommandFunc)(CommandChain*, CommandCallback,
mozilla::dom::NetworkResultOptions& aResult);
typedef void (*MessageCallback)(mozilla::dom::NetworkResultOptions& aResult);
typedef void (*ErrorCallback)(NetworkParams& aOptions,
mozilla::dom::NetworkResultOptions& aResult);
class NetworkParams
{
public:
NetworkParams() {
}
NetworkParams(const mozilla::dom::NetworkCommandOptions& aOther) {
#define COPY_SEQUENCE_FIELD(prop, type) \
if (aOther.prop.WasPassed()) { \
mozilla::dom::Sequence<type > const & currentValue = aOther.prop.InternalValue(); \
uint32_t length = currentValue.Length(); \
for (uint32_t idx = 0; idx < length; idx++) { \
prop.AppendElement(currentValue[idx]); \
} \
}
#define COPY_OPT_STRING_FIELD(prop, defaultValue) \
if (aOther.prop.WasPassed()) { \
if (aOther.prop.Value().EqualsLiteral("null")) { \
prop = defaultValue; \
} else { \
prop = aOther.prop.Value(); \
} \
} else { \
prop = defaultValue; \
}
#define COPY_OPT_FIELD(prop, defaultValue) \
if (aOther.prop.WasPassed()) { \
prop = aOther.prop.Value(); \
} else { \
prop = defaultValue; \
}
#define COPY_FIELD(prop) prop = aOther.prop;
COPY_FIELD(mId)
COPY_FIELD(mCmd)
COPY_OPT_STRING_FIELD(mDomain, EmptyString())
COPY_OPT_STRING_FIELD(mGateway, EmptyString())
COPY_SEQUENCE_FIELD(mGateways, nsString)
COPY_OPT_STRING_FIELD(mIfname, EmptyString())
COPY_OPT_STRING_FIELD(mIp, EmptyString())
COPY_OPT_FIELD(mPrefixLength, 0)
COPY_OPT_STRING_FIELD(mMode, EmptyString())
COPY_OPT_FIELD(mReport, false)
COPY_OPT_FIELD(mEnabled, false)
COPY_OPT_STRING_FIELD(mWifictrlinterfacename, EmptyString())
COPY_OPT_STRING_FIELD(mInternalIfname, EmptyString())
COPY_OPT_STRING_FIELD(mExternalIfname, EmptyString())
COPY_OPT_FIELD(mEnable, false)
COPY_OPT_STRING_FIELD(mSsid, EmptyString())
COPY_OPT_STRING_FIELD(mSecurity, EmptyString())
COPY_OPT_STRING_FIELD(mKey, EmptyString())
COPY_OPT_STRING_FIELD(mPrefix, EmptyString())
COPY_OPT_STRING_FIELD(mLink, EmptyString())
COPY_SEQUENCE_FIELD(mInterfaceList, nsString)
COPY_OPT_STRING_FIELD(mWifiStartIp, EmptyString())
COPY_OPT_STRING_FIELD(mWifiEndIp, EmptyString())
COPY_OPT_STRING_FIELD(mUsbStartIp, EmptyString())
COPY_OPT_STRING_FIELD(mUsbEndIp, EmptyString())
COPY_OPT_STRING_FIELD(mDns1, EmptyString())
COPY_OPT_STRING_FIELD(mDns2, EmptyString())
COPY_SEQUENCE_FIELD(mDnses, nsString)
COPY_OPT_STRING_FIELD(mStartIp, EmptyString())
COPY_OPT_STRING_FIELD(mEndIp, EmptyString())
COPY_OPT_STRING_FIELD(mServerIp, EmptyString())
COPY_OPT_STRING_FIELD(mMaskLength, EmptyString())
COPY_OPT_STRING_FIELD(mPreInternalIfname, EmptyString())
COPY_OPT_STRING_FIELD(mPreExternalIfname, EmptyString())
COPY_OPT_STRING_FIELD(mCurInternalIfname, EmptyString())
COPY_OPT_STRING_FIELD(mCurExternalIfname, EmptyString())
COPY_OPT_FIELD(mThreshold, -1)
COPY_OPT_FIELD(mIpaddr, 0)
COPY_OPT_FIELD(mMask, 0)
COPY_OPT_FIELD(mGateway_long, 0)
COPY_OPT_FIELD(mDns1_long, 0)
COPY_OPT_FIELD(mDns2_long, 0)
COPY_OPT_FIELD(mMtu, 0)
mLoopIndex = 0;
#undef COPY_SEQUENCE_FIELD
#undef COPY_OPT_STRING_FIELD
#undef COPY_OPT_FIELD
#undef COPY_FIELD
}
// Followings attributes are 1-to-1 mapping to NetworkCommandOptions.
int32_t mId;
nsString mCmd;
nsString mDomain;
nsString mGateway;
nsTArray<nsString> mGateways;
nsString mIfname;
nsString mIp;
uint32_t mPrefixLength;
nsString mMode;
bool mReport;
bool mEnabled;
nsString mWifictrlinterfacename;
nsString mInternalIfname;
nsString mExternalIfname;
bool mEnable;
nsString mSsid;
nsString mSecurity;
nsString mKey;
nsString mPrefix;
nsString mLink;
nsTArray<nsString> mInterfaceList;
nsString mWifiStartIp;
nsString mWifiEndIp;
nsString mUsbStartIp;
nsString mUsbEndIp;
nsString mDns1;
nsString mDns2;
nsTArray<nsString> mDnses;
nsString mStartIp;
nsString mEndIp;
nsString mServerIp;
nsString mMaskLength;
nsString mPreInternalIfname;
nsString mPreExternalIfname;
nsString mCurInternalIfname;
nsString mCurExternalIfname;
long long mThreshold;
long mIpaddr;
long mMask;
long mGateway_long;
long mDns1_long;
long mDns2_long;
long mMtu;
// Auxiliary information required to carry accros command chain.
int mNetId; // A locally defined id per interface.
uint32_t mLoopIndex; // Loop index for adding/removing multiple gateways.
};
// CommandChain store the necessary information to execute command one by one.
// Including :
// 1. Command parameters.
// 2. Command list.
// 3. Error callback function.
// 4. Index of current execution command.
class CommandChain final
{
public:
CommandChain(const NetworkParams& aParams,
const CommandFunc aCmds[],
uint32_t aLength,
ErrorCallback aError)
: mIndex(-1)
, mParams(aParams)
, mCommands(aCmds)
, mLength(aLength)
, mError(aError) {
}
NetworkParams&
getParams()
{
return mParams;
};
CommandFunc
getNextCommand()
{
mIndex++;
return mIndex < mLength ? mCommands[mIndex] : nullptr;
};
ErrorCallback
getErrorCallback() const
{
return mError;
};
private:
uint32_t mIndex;
NetworkParams mParams;
const CommandFunc* mCommands;
uint32_t mLength;
ErrorCallback mError;
};
// A helper class to easily construct a resolved
// or a pending result for command execution.
class CommandResult
{
public:
struct Pending {};
public:
CommandResult(int32_t aResultCode);
CommandResult(const mozilla::dom::NetworkResultOptions& aResult);
CommandResult(const Pending&);
bool isPending() const;
mozilla::dom::NetworkResultOptions mResult;
private:
bool mIsPending;
};
class NetworkUtils final
{
public:
NetworkUtils(MessageCallback aCallback);
~NetworkUtils();
void ExecuteCommand(NetworkParams aOptions);
void onNetdMessage(mozilla::ipc::NetdCommand* aCommand);
MessageCallback getMessageCallback() { return mMessageCallback; }
private:
/**
* Commands supported by NetworkUtils.
*/
CommandResult configureInterface(NetworkParams& aOptions);
CommandResult dhcpRequest(NetworkParams& aOptions);
CommandResult stopDhcp(NetworkParams& aOptions);
CommandResult enableInterface(NetworkParams& aOptions);
CommandResult disableInterface(NetworkParams& aOptions);
CommandResult resetConnections(NetworkParams& aOptions);
CommandResult setDefaultRoute(NetworkParams& aOptions);
CommandResult addHostRoute(NetworkParams& aOptions);
CommandResult removeDefaultRoute(NetworkParams& aOptions);
CommandResult removeHostRoute(NetworkParams& aOptions);
CommandResult removeNetworkRoute(NetworkParams& aOptions);
CommandResult setDNS(NetworkParams& aOptions);
CommandResult addSecondaryRoute(NetworkParams& aOptions);
CommandResult removeSecondaryRoute(NetworkParams& aOptions);
CommandResult setNetworkInterfaceAlarm(NetworkParams& aOptions);
CommandResult enableNetworkInterfaceAlarm(NetworkParams& aOptions);
CommandResult disableNetworkInterfaceAlarm(NetworkParams& aOptions);
CommandResult setTetheringAlarm(NetworkParams& aOptions);
CommandResult removeTetheringAlarm(NetworkParams& aOptions);
CommandResult getTetheringStatus(NetworkParams& aOptions);
CommandResult setWifiOperationMode(NetworkParams& aOptions);
CommandResult setDhcpServer(NetworkParams& aOptions);
CommandResult setWifiTethering(NetworkParams& aOptions);
CommandResult setUSBTethering(NetworkParams& aOptions);
CommandResult enableUsbRndis(NetworkParams& aOptions);
CommandResult updateUpStream(NetworkParams& aOptions);
CommandResult createNetwork(NetworkParams& aOptions);
CommandResult destroyNetwork(NetworkParams& aOptions);
CommandResult getNetId(NetworkParams& aOptions);
CommandResult setMtu(NetworkParams& aOptions);
CommandResult getInterfaces(NetworkParams& aOptions);
CommandResult getInterfaceConfig(NetworkParams& aOptions);
CommandResult setInterfaceConfig(NetworkParams& aOptions);
CommandResult addHostRouteLegacy(NetworkParams& aOptions);
CommandResult removeHostRouteLegacy(NetworkParams& aOptions);
CommandResult setDefaultRouteLegacy(NetworkParams& aOptions);
CommandResult removeDefaultRouteLegacy(NetworkParams& aOptions);
CommandResult removeNetworkRouteLegacy(NetworkParams& aOptions);
/**
* function pointer array holds all netd commands should be executed
* in sequence to accomplish a given command by other module.
*/
static const CommandFunc sWifiEnableChain[];
static const CommandFunc sWifiDisableChain[];
static const CommandFunc sWifiFailChain[];
static const CommandFunc sWifiRetryChain[];
static const CommandFunc sWifiOperationModeChain[];
static const CommandFunc sUSBEnableChain[];
static const CommandFunc sUSBDisableChain[];
static const CommandFunc sUSBFailChain[];
static const CommandFunc sUpdateUpStreamChain[];
static const CommandFunc sStartDhcpServerChain[];
static const CommandFunc sStopDhcpServerChain[];
static const CommandFunc sNetworkInterfaceEnableAlarmChain[];
static const CommandFunc sNetworkInterfaceDisableAlarmChain[];
static const CommandFunc sNetworkInterfaceSetAlarmChain[];
static const CommandFunc sTetheringInterfaceSetAlarmChain[];
static const CommandFunc sTetheringInterfaceRemoveAlarmChain[];
static const CommandFunc sTetheringGetStatusChain[];
static const CommandFunc sGetInterfacesChain[];
static const CommandFunc sGetInterfaceConfigChain[];
static const CommandFunc sSetInterfaceConfigChain[];
/**
* Individual netd command stored in command chain.
*/
#define PARAMS CommandChain* aChain, CommandCallback aCallback, \
mozilla::dom::NetworkResultOptions& aResult
static void wifiFirmwareReload(PARAMS);
static void startAccessPointDriver(PARAMS);
static void stopAccessPointDriver(PARAMS);
static void setAccessPoint(PARAMS);
static void cleanUpStream(PARAMS);
static void createUpStream(PARAMS);
static void startSoftAP(PARAMS);
static void stopSoftAP(PARAMS);
static void clearWifiTetherParms(PARAMS);
static void enableAlarm(PARAMS);
static void disableAlarm(PARAMS);
static void setQuota(PARAMS);
static void removeQuota(PARAMS);
static void setAlarm(PARAMS);
static void removeAlarm(PARAMS);
static void setGlobalAlarm(PARAMS);
static void removeGlobalAlarm(PARAMS);
static void tetherInterface(PARAMS);
static void addInterfaceToLocalNetwork(PARAMS);
static void addRouteToLocalNetwork(PARAMS);
static void preTetherInterfaceList(PARAMS);
static void postTetherInterfaceList(PARAMS);
static void addUpstreamInterface(PARAMS);
static void removeUpstreamInterface(PARAMS);
static void setIpForwardingEnabled(PARAMS);
static void tetheringStatus(PARAMS);
static void stopTethering(PARAMS);
static void startTethering(PARAMS);
static void untetherInterface(PARAMS);
static void removeInterfaceFromLocalNetwork(PARAMS);
static void setDnsForwarders(PARAMS);
static void enableNat(PARAMS);
static void disableNat(PARAMS);
static void setDefaultInterface(PARAMS);
static void setInterfaceDns(PARAMS);
static void getInterfaceList(PARAMS);
static void getConfig(PARAMS);
static void setConfig(PARAMS);
static void wifiTetheringSuccess(PARAMS);
static void usbTetheringSuccess(PARAMS);
static void networkInterfaceAlarmSuccess(PARAMS);
static void updateUpStreamSuccess(PARAMS);
static void setDhcpServerSuccess(PARAMS);
static void wifiOperationModeSuccess(PARAMS);
static void clearAddrForInterface(PARAMS);
static void createNetwork(PARAMS);
static void destroyNetwork(PARAMS);
static void addInterfaceToNetwork(PARAMS);
static void addDefaultRouteToNetwork(PARAMS);
static void setDefaultNetwork(PARAMS);
static void removeDefaultRoute(PARAMS);
static void removeNetworkRouteSuccess(PARAMS);
static void removeNetworkRoute(PARAMS);
static void addRouteToInterface(PARAMS);
static void removeRouteFromInterface(PARAMS);
static void modifyRouteOnInterface(PARAMS, bool aDoAdd);
static void enableIpv6(PARAMS);
static void disableIpv6(PARAMS);
static void setMtu(PARAMS);
static void setIpv6Enabled(PARAMS, bool aEnabled);
static void addRouteToSecondaryTable(PARAMS);
static void removeRouteFromSecondaryTable(PARAMS);
static void defaultAsyncSuccessHandler(PARAMS);
static void getInterfacesSuccess(PARAMS);
static void getInterfaceConfigSuccess(PARAMS);
static void setInterfaceConfigSuccess(PARAMS);
#undef PARAMS
/**
* Error callback function executed when a command is fail.
*/
#define PARAMS NetworkParams& aOptions, \
mozilla::dom::NetworkResultOptions& aResult
static void wifiTetheringFail(PARAMS);
static void wifiOperationModeFail(PARAMS);
static void usbTetheringFail(PARAMS);
static void updateUpStreamFail(PARAMS);
static void setDhcpServerFail(PARAMS);
static void networkInterfaceAlarmFail(PARAMS);
static void setDnsFail(PARAMS);
static void defaultAsyncFailureHandler(PARAMS);
static void getInterfacesFail(PARAMS);
static void getInterfaceConfigFail(PARAMS);
static void setInterfaceConfigFail(PARAMS);
#undef PARAMS
/**
* Command chain processing functions.
*/
static void next(CommandChain* aChain, bool aError,
mozilla::dom::NetworkResultOptions& aResult);
static void nextNetdCommand();
static void doCommand(const char* aCommand, CommandChain* aChain, CommandCallback aCallback);
/**
* Notify broadcast message to main thread.
*/
void sendBroadcastMessage(uint32_t code, char* reason);
/**
* Utility functions.
*/
CommandResult checkUsbRndisState(NetworkParams& aOptions);
void dumpParams(NetworkParams& aOptions, const char* aType);
static void escapeQuote(nsCString& aString);
inline uint32_t netdResponseType(uint32_t code);
inline bool isBroadcastMessage(uint32_t code);
inline bool isError(uint32_t code);
inline bool isComplete(uint32_t code);
inline bool isProceeding(uint32_t code);
void Shutdown();
static void runNextQueuedCommandChain();
static void finalizeSuccess(CommandChain* aChain,
mozilla::dom::NetworkResultOptions& aResult);
template<size_t N>
static void runChain(const NetworkParams& aParams,
const CommandFunc (&aCmds)[N],
ErrorCallback aError);
static nsCString getSubnetIp(const nsCString& aIp, int aPrefixLength);
/**
* Callback function to send netd result to main thread.
*/
MessageCallback mMessageCallback;
/*
* Utility class to access libnetutils.
*/
nsAutoPtr<NetUtils> mNetUtils;
NetIdManager mNetIdManager;
};
#endif

Просмотреть файл

@ -1,271 +0,0 @@
/* 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/. */
#include "NetworkWorker.h"
#include "NetworkUtils.h"
#include <nsThreadUtils.h>
#include "mozilla/ModuleUtils.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/ToJSValue.h"
#include "nsAutoPtr.h"
#include "nsXULAppAPI.h"
#define NS_NETWORKWORKER_CID \
{ 0x6df093e1, 0x8127, 0x4fa7, {0x90, 0x13, 0xa3, 0xaa, 0xa7, 0x79, 0xbb, 0xdd} }
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::ipc;
namespace mozilla {
nsCOMPtr<nsIThread> gWorkerThread;
// The singleton network worker, to be used on the main thread.
StaticRefPtr<NetworkWorker> gNetworkWorker;
// The singleton networkutils class, that can be used on any thread.
static nsAutoPtr<NetworkUtils> gNetworkUtils;
// Runnable used dispatch command result on the main thread.
class NetworkResultDispatcher : public Runnable
{
public:
NetworkResultDispatcher(const NetworkResultOptions& aResult)
: mResult(aResult)
{
MOZ_ASSERT(!NS_IsMainThread());
}
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
if (gNetworkWorker) {
gNetworkWorker->DispatchNetworkResult(mResult);
}
return NS_OK;
}
private:
NetworkResultOptions mResult;
};
// Runnable used dispatch netd command on the worker thread.
class NetworkCommandDispatcher : public Runnable
{
public:
NetworkCommandDispatcher(const NetworkParams& aParams)
: mParams(aParams)
{
MOZ_ASSERT(NS_IsMainThread());
}
NS_IMETHOD Run() override
{
MOZ_ASSERT(!NS_IsMainThread());
if (gNetworkUtils) {
gNetworkUtils->ExecuteCommand(mParams);
}
return NS_OK;
}
private:
NetworkParams mParams;
};
// Runnable used dispatch netd result on the worker thread.
class NetdEventRunnable : public Runnable
{
public:
NetdEventRunnable(NetdCommand* aCommand)
: mCommand(aCommand)
{
MOZ_ASSERT(!NS_IsMainThread());
}
NS_IMETHOD Run() override
{
MOZ_ASSERT(!NS_IsMainThread());
if (gNetworkUtils) {
gNetworkUtils->onNetdMessage(mCommand);
}
return NS_OK;
}
private:
nsAutoPtr<NetdCommand> mCommand;
};
class NetdMessageConsumer : public NetdConsumer
{
public:
NetdMessageConsumer()
{
MOZ_ASSERT(NS_IsMainThread());
}
void MessageReceived(NetdCommand* aCommand)
{
MOZ_ASSERT(!NS_IsMainThread());
nsCOMPtr<nsIRunnable> runnable = new NetdEventRunnable(aCommand);
if (gWorkerThread) {
gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
}
}
};
NS_IMPL_ISUPPORTS(NetworkWorker, nsINetworkWorker)
NetworkWorker::NetworkWorker()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!gNetworkWorker);
}
NetworkWorker::~NetworkWorker()
{
MOZ_ASSERT(!gNetworkWorker);
MOZ_ASSERT(!mListener);
}
already_AddRefed<NetworkWorker>
NetworkWorker::FactoryCreate()
{
if (!XRE_IsParentProcess()) {
return nullptr;
}
MOZ_ASSERT(NS_IsMainThread());
if (!gNetworkWorker) {
gNetworkWorker = new NetworkWorker();
ClearOnShutdown(&gNetworkWorker);
gNetworkUtils = new NetworkUtils(NetworkWorker::NotifyResult);
ClearOnShutdown(&gNetworkUtils);
}
RefPtr<NetworkWorker> worker = gNetworkWorker.get();
return worker.forget();
}
NS_IMETHODIMP
NetworkWorker::Start(nsINetworkEventListener* aListener)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aListener);
if (mListener) {
return NS_OK;
}
nsresult rv;
rv = NS_NewNamedThread("NetworkWorker", getter_AddRefs(gWorkerThread));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create network control thread");
return NS_ERROR_FAILURE;
}
StartNetd(new NetdMessageConsumer());
mListener = aListener;
return NS_OK;
}
NS_IMETHODIMP
NetworkWorker::Shutdown()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mListener) {
return NS_OK;
}
StopNetd();
gWorkerThread->Shutdown();
gWorkerThread = nullptr;
mListener = nullptr;
return NS_OK;
}
// Receive command from main thread (NetworkService.js).
NS_IMETHODIMP
NetworkWorker::PostMessage(JS::Handle<JS::Value> aOptions, JSContext* aCx)
{
MOZ_ASSERT(NS_IsMainThread());
NetworkCommandOptions options;
if (!options.Init(aCx, aOptions)) {
NS_WARNING("Bad dictionary passed to NetworkWorker::SendCommand");
return NS_ERROR_FAILURE;
}
// Dispatch the command to the control thread.
NetworkParams NetworkParams(options);
nsCOMPtr<nsIRunnable> runnable = new NetworkCommandDispatcher(NetworkParams);
if (gWorkerThread) {
gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
}
return NS_OK;
}
void
NetworkWorker::DispatchNetworkResult(const NetworkResultOptions& aOptions)
{
MOZ_ASSERT(NS_IsMainThread());
mozilla::AutoSafeJSContext cx;
JS::RootedValue val(cx);
if (!ToJSValue(cx, aOptions, &val)) {
return;
}
// Call the listener with a JS value.
if (mListener) {
mListener->OnEvent(val);
}
}
// Callback function from network worker thread to update result on main thread.
void
NetworkWorker::NotifyResult(NetworkResultOptions& aResult)
{
MOZ_ASSERT(!NS_IsMainThread());
nsCOMPtr<nsIRunnable> runnable = new NetworkResultDispatcher(aResult);
NS_DispatchToMainThread(runnable);
}
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(NetworkWorker,
NetworkWorker::FactoryCreate)
NS_DEFINE_NAMED_CID(NS_NETWORKWORKER_CID);
static const mozilla::Module::CIDEntry kNetworkWorkerCIDs[] = {
{ &kNS_NETWORKWORKER_CID, false, nullptr, NetworkWorkerConstructor },
{ nullptr }
};
static const mozilla::Module::ContractIDEntry kNetworkWorkerContracts[] = {
{ "@mozilla.org/network/worker;1", &kNS_NETWORKWORKER_CID },
{ nullptr }
};
static const mozilla::Module kNetworkWorkerModule = {
mozilla::Module::kVersion,
kNetworkWorkerCIDs,
kNetworkWorkerContracts,
nullptr
};
} // namespace mozilla
NSMODULE_DEFN(NetworkWorkerModule) = &kNetworkWorkerModule;

Просмотреть файл

@ -1,37 +0,0 @@
/* 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 NetworkWorker_h
#define NetworkWorker_h
#include "mozilla/dom/NetworkOptionsBinding.h"
#include "mozilla/ipc/Netd.h"
#include "nsINetworkWorker.h"
#include "nsCOMPtr.h"
#include "nsThread.h"
namespace mozilla {
class NetworkWorker final : public nsINetworkWorker
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSINETWORKWORKER
static already_AddRefed<NetworkWorker> FactoryCreate();
void DispatchNetworkResult(const mozilla::dom::NetworkResultOptions& aOptions);
private:
NetworkWorker();
~NetworkWorker();
static void NotifyResult(mozilla::dom::NetworkResultOptions& aResult);
nsCOMPtr<nsINetworkEventListener> mListener;
};
} // namespace mozilla
#endif // NetworkWorker_h

Просмотреть файл

@ -1,251 +0,0 @@
/* 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/. */
#include "OpenFileFinder.h"
#include "mozilla/FileUtils.h"
#include "nsPrintfCString.h"
#include <sys/stat.h>
#include <errno.h>
#undef USE_DEBUG
#define USE_DEBUG 0
#undef LOG
#undef LOGW
#undef ERR
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "OpenFileFinder", ## args)
#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "OpenFileFinder", ## args)
#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "OpenFileFinder", ## args)
#undef DBG
#if USE_DEBUG
#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, "OpenFileFinder" , ## args)
#else
#define DBG(args...)
#endif
namespace mozilla {
namespace system {
OpenFileFinder::OpenFileFinder(const nsACString& aPath,
bool aCheckIsB2gOrDescendant /* = true */)
: mPath(aPath),
mProcDir(nullptr),
mFdDir(nullptr),
mPid(0),
mCheckIsB2gOrDescendant(aCheckIsB2gOrDescendant)
{
// We assume that we're running in the parent process
mMyPid = getpid();
}
OpenFileFinder::~OpenFileFinder()
{
Close();
}
bool
OpenFileFinder::First(OpenFileFinder::Info* aInfo)
{
Close();
mProcDir = opendir("/proc");
if (!mProcDir) {
return false;
}
mState = NEXT_PID;
return Next(aInfo);
}
bool
OpenFileFinder::Next(OpenFileFinder::Info* aInfo)
{
// NOTE: This function calls readdir and readlink, neither of which should
// block since we're using the proc filesystem, which is a purely
// kernel in-memory filesystem and doesn't depend on external driver
// behaviour.
while (mState != DONE) {
switch (mState) {
case NEXT_PID: {
struct dirent *pidEntry;
pidEntry = readdir(mProcDir);
if (!pidEntry) {
mState = DONE;
break;
}
char *endPtr;
mPid = strtol(pidEntry->d_name, &endPtr, 10);
if (mPid == 0 || *endPtr != '\0') {
// Not a +ve number - ignore
continue;
}
// We've found a /proc/PID directory. Scan open file descriptors.
if (mFdDir) {
closedir(mFdDir);
}
nsPrintfCString fdDirPath("/proc/%d/fd", mPid);
mFdDir = opendir(fdDirPath.get());
if (!mFdDir) {
continue;
}
mState = CHECK_FDS;
}
// Fall through
case CHECK_FDS: {
struct dirent *fdEntry;
while((fdEntry = readdir(mFdDir))) {
if (!strcmp(fdEntry->d_name, ".") ||
!strcmp(fdEntry->d_name, "..")) {
continue;
}
nsPrintfCString fdSymLink("/proc/%d/fd/%s", mPid, fdEntry->d_name);
nsCString resolvedPath;
if (ReadSymLink(fdSymLink, resolvedPath) && PathMatches(resolvedPath)) {
// We found an open file contained within the directory tree passed
// into the constructor.
FillInfo(aInfo, resolvedPath);
// If sCheckIsB2gOrDescendant is set false, the caller cares about
// all processes which have open files. If sCheckIsB2gOrDescendant
// is set false, we only care about the b2g proccess or its descendants.
if (!mCheckIsB2gOrDescendant || aInfo->mIsB2gOrDescendant) {
return true;
}
LOG("Ignore process(%d), not a b2g process or its descendant.",
aInfo->mPid);
}
}
// We've checked all of the files for this pid, move onto the next one.
mState = NEXT_PID;
continue;
}
case DONE:
default:
mState = DONE; // covers the default case
break;
}
}
return false;
}
void
OpenFileFinder::Close()
{
if (mFdDir) {
closedir(mFdDir);
}
if (mProcDir) {
closedir(mProcDir);
}
}
void
OpenFileFinder::FillInfo(OpenFileFinder::Info* aInfo, const nsACString& aPath)
{
aInfo->mFileName = aPath;
aInfo->mPid = mPid;
nsPrintfCString exePath("/proc/%d/exe", mPid);
ReadSymLink(exePath, aInfo->mExe);
aInfo->mComm.Truncate();
aInfo->mAppName.Truncate();
nsPrintfCString statPath("/proc/%d/stat", mPid);
nsCString statString;
statString.SetLength(200);
char *stat = statString.BeginWriting();
if (!stat) {
return;
}
ReadSysFile(statPath.get(), stat, statString.Length());
// The stat line includes the comm field, surrounded by parenthesis.
// However, the contents of the comm field itself is arbitrary and
// and can include ')', so we search for the rightmost ) as being
// the end of the comm field.
char *closeParen = strrchr(stat, ')');
if (!closeParen) {
return;
}
char *openParen = strchr(stat, '(');
if (!openParen) {
return;
}
if (openParen >= closeParen) {
return;
}
nsDependentCSubstring comm(&openParen[1], closeParen - openParen - 1);
aInfo->mComm = comm;
// There is a single character field after the comm and then
// the parent pid (the field we're interested in).
// ) X ppid
// 01234
int ppid = atoi(&closeParen[4]);
if (mPid == mMyPid) {
// This is chrome process
aInfo->mIsB2gOrDescendant = true;
DBG("Chrome process has open file(s)");
return;
}
// For the rest (non-chrome process), we recursively check the ppid to know
// it is a descendant of b2g or not. See bug 931456.
while (ppid != mMyPid && ppid != 1) {
DBG("Process(%d) is not forked from b2g(%d) or Init(1), keep looking",
ppid, mMyPid);
nsPrintfCString ppStatPath("/proc/%d/stat", ppid);
ReadSysFile(ppStatPath.get(), stat, statString.Length());
closeParen = strrchr(stat, ')');
if (!closeParen) {
return;
}
ppid = atoi(&closeParen[4]);
}
if (ppid == 1) {
// This is a not a b2g process.
DBG("Non-b2g process has open file(s)");
aInfo->mIsB2gOrDescendant = false;
return;
}
if (ppid == mMyPid) {
// This is a descendant of b2g.
DBG("Child process of chrome process has open file(s)");
aInfo->mIsB2gOrDescendant = true;
}
// This looks like a content process. The comm field will be the
// app name.
aInfo->mAppName = aInfo->mComm;
}
bool
OpenFileFinder::ReadSymLink(const nsACString& aSymLink, nsACString& aOutPath)
{
aOutPath.Truncate();
const char *symLink = aSymLink.BeginReading();
// Verify that we actually have a symlink.
struct stat st;
if (lstat(symLink, &st)) {
return false;
}
if ((st.st_mode & S_IFMT) != S_IFLNK) {
return false;
}
// Contrary to the documentation st.st_size doesn't seem to be a reliable
// indication of the length when reading from /proc, so we use a fixed
// size buffer instead.
char resolvedSymLink[PATH_MAX];
ssize_t pathLength = readlink(symLink, resolvedSymLink,
sizeof(resolvedSymLink) - 1);
if (pathLength <= 0) {
return false;
}
resolvedSymLink[pathLength] = '\0';
aOutPath.Assign(resolvedSymLink);
return true;
}
} // system
} // mozilla

Просмотреть файл

@ -1,63 +0,0 @@
/* 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_openfilefinder_h__
#define mozilla_system_openfilefinder_h__
#include "nsString.h"
#include <dirent.h>
namespace mozilla {
namespace system {
class OpenFileFinder
{
public:
enum State
{
NEXT_PID,
CHECK_FDS,
DONE
};
class Info
{
public:
nsCString mFileName; // name of the the open file
nsCString mAppName; // App which has the file open (if it's a b2g app)
pid_t mPid; // pid of the process which has the file open
nsCString mComm; // comm associated with pid
nsCString mExe; // executable name associated with pid
bool mIsB2gOrDescendant; // this is b2g/its descendant or not
};
OpenFileFinder(const nsACString& aPath, bool aCheckIsB2gOrDescendant = true);
~OpenFileFinder();
bool First(Info* aInfo); // Return the first open file
bool Next(Info* aInfo); // Return the next open file
void Close();
private:
void FillInfo(Info *aInfo, const nsACString& aPath);
bool ReadSymLink(const nsACString& aSymLink, nsACString& aOutPath);
bool PathMatches(const nsACString& aPath)
{
return Substring(aPath, 0, mPath.Length()).Equals(mPath);
}
State mState; // Keeps track of what we're doing.
nsCString mPath; // Only report files contained within this directory tree
DIR* mProcDir; // Used for scanning /proc
DIR* mFdDir; // Used for scanning /proc/PID/fd
int mPid; // PID currently being processed
pid_t mMyPid; // PID of parent process, we assume we're running on it.
bool mCheckIsB2gOrDescendant; // Do we care about non-b2g process?
};
} // system
} // mozilla
#endif // mozilla_system_nsvolume_h__

Просмотреть файл

@ -1,338 +0,0 @@
/* 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/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "RIL", function () {
let obj = {};
Cu.import("resource://gre/modules/ril_consts.js", obj);
return obj;
});
/**
* RILSystemMessenger
*/
this.RILSystemMessenger = function() {};
RILSystemMessenger.prototype = {
/**
* Hook of Broadcast function
*
* @param aType
* The type of the message to be sent.
* @param aMessage
* The message object to be broadcasted.
*/
broadcastMessage: function(aType, aMessage) {
// Function stub to be replaced by the owner of this messenger.
},
/**
* Hook of the function to create MozStkCommand message.
* @param aStkProactiveCmd
* nsIStkProactiveCmd instance.
*
* @return a JS object which complies the dictionary of MozStkCommand defined
* in MozStkCommandEvent.webidl
*/
createCommandMessage: function(aStkProactiveCmd) {
// Function stub to be replaced by the owner of this messenger.
},
/**
* Wrapper to send "telephony-new-call" system message.
*/
notifyNewCall: function() {
this.broadcastMessage("telephony-new-call", {});
},
/**
* Wrapper to send "telephony-call-ended" system message.
*/
notifyCallEnded: function(aServiceId, aNumber, aCdmaWaitingNumber, aEmergency,
aDuration, aOutgoing, aHangUpLocal) {
let data = {
serviceId: aServiceId,
number: aNumber,
emergency: aEmergency,
duration: aDuration,
direction: aOutgoing ? "outgoing" : "incoming",
hangUpLocal: aHangUpLocal
};
if (aCdmaWaitingNumber != null) {
data.secondNumber = aCdmaWaitingNumber;
}
this.broadcastMessage("telephony-call-ended", data);
},
_convertSmsMessageClass: function(aMessageClass) {
return RIL.GECKO_SMS_MESSAGE_CLASSES[aMessageClass] || null;
},
_convertSmsDelivery: function(aDelivery) {
return ["received", "sending", "sent", "error"][aDelivery] || null;
},
_convertSmsDeliveryStatus: function(aDeliveryStatus) {
return [
RIL.GECKO_SMS_DELIVERY_STATUS_NOT_APPLICABLE,
RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS,
RIL.GECKO_SMS_DELIVERY_STATUS_PENDING,
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR
][aDeliveryStatus] || null;
},
/**
* Wrapper to send 'sms-received', 'sms-delivery-success', 'sms-sent',
* 'sms-failed', 'sms-delivery-error' system message.
*/
notifySms: function(aNotificationType, aId, aThreadId, aIccId, aDelivery,
aDeliveryStatus, aSender, aReceiver, aBody, aMessageClass,
aTimestamp, aSentTimestamp, aDeliveryTimestamp, aRead) {
let msgType = [
"sms-received",
"sms-sent",
"sms-delivery-success",
"sms-failed",
"sms-delivery-error"
][aNotificationType];
if (!msgType) {
throw new Error("Invalid Notification Type: " + aNotificationType);
}
this.broadcastMessage(msgType, {
iccId: aIccId,
type: "sms",
id: aId,
threadId: aThreadId,
delivery: this._convertSmsDelivery(aDelivery),
deliveryStatus: this._convertSmsDeliveryStatus(aDeliveryStatus),
sender: aSender,
receiver: aReceiver,
body: aBody,
messageClass: this._convertSmsMessageClass(aMessageClass),
timestamp: aTimestamp,
sentTimestamp: aSentTimestamp,
deliveryTimestamp: aDeliveryTimestamp,
read: aRead
});
},
_convertCbGsmGeographicalScope: function(aGeographicalScope) {
return RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[aGeographicalScope] || null;
},
_convertCbMessageClass: function(aMessageClass) {
return RIL.GECKO_SMS_MESSAGE_CLASSES[aMessageClass] || null;
},
_convertCbEtwsWarningType: function(aWarningType) {
return RIL.CB_ETWS_WARNING_TYPE_NAMES[aWarningType] || null;
},
/**
* Wrapper to send 'cellbroadcast-received' system message.
*/
notifyCbMessageReceived: function(aServiceId, aGsmGeographicalScope, aMessageCode,
aMessageId, aLanguage, aBody, aMessageClass,
aTimestamp, aCdmaServiceCategory, aHasEtwsInfo,
aEtwsWarningType, aEtwsEmergencyUserAlert, aEtwsPopup) {
// Align the same layout to MozCellBroadcastMessage
let data = {
serviceId: aServiceId,
gsmGeographicalScope: this._convertCbGsmGeographicalScope(aGsmGeographicalScope),
messageCode: aMessageCode,
messageId: aMessageId,
language: aLanguage,
body: aBody,
messageClass: this._convertCbMessageClass(aMessageClass),
timestamp: aTimestamp,
cdmaServiceCategory: null,
etws: null
};
if (aHasEtwsInfo) {
data.etws = {
warningType: this._convertCbEtwsWarningType(aEtwsWarningType),
emergencyUserAlert: aEtwsEmergencyUserAlert,
popup: aEtwsPopup
};
}
if (aCdmaServiceCategory !=
Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID) {
data.cdmaServiceCategory = aCdmaServiceCategory;
}
this.broadcastMessage("cellbroadcast-received", data);
},
/**
* Wrapper to send 'ussd-received' system message.
*/
notifyUssdReceived: function(aServiceId, aMessage, aSessionEnded) {
this.broadcastMessage("ussd-received", {
serviceId: aServiceId,
message: aMessage,
sessionEnded: aSessionEnded
});
},
/**
* Wrapper to send 'cdma-info-rec-received' system message with Display Info.
*/
notifyCdmaInfoRecDisplay: function(aServiceId, aDisplay) {
this.broadcastMessage("cdma-info-rec-received", {
clientId: aServiceId,
display: aDisplay
});
},
/**
* Wrapper to send 'cdma-info-rec-received' system message with Called Party
* Number Info.
*/
notifyCdmaInfoRecCalledPartyNumber: function(aServiceId, aType, aPlan,
aNumber, aPi, aSi) {
this.broadcastMessage("cdma-info-rec-received", {
clientId: aServiceId,
calledNumber: {
type: aType,
plan: aPlan,
number: aNumber,
pi: aPi,
si: aSi
}
});
},
/**
* Wrapper to send 'cdma-info-rec-received' system message with Calling Party
* Number Info.
*/
notifyCdmaInfoRecCallingPartyNumber: function(aServiceId, aType, aPlan,
aNumber, aPi, aSi) {
this.broadcastMessage("cdma-info-rec-received", {
clientId: aServiceId,
callingNumber: {
type: aType,
plan: aPlan,
number: aNumber,
pi: aPi,
si: aSi
}
});
},
/**
* Wrapper to send 'cdma-info-rec-received' system message with Connected Party
* Number Info.
*/
notifyCdmaInfoRecConnectedPartyNumber: function(aServiceId, aType, aPlan,
aNumber, aPi, aSi) {
this.broadcastMessage("cdma-info-rec-received", {
clientId: aServiceId,
connectedNumber: {
type: aType,
plan: aPlan,
number: aNumber,
pi: aPi,
si: aSi
}
});
},
/**
* Wrapper to send 'cdma-info-rec-received' system message with Signal Info.
*/
notifyCdmaInfoRecSignal: function(aServiceId, aType, aAlertPitch, aSignal) {
this.broadcastMessage("cdma-info-rec-received", {
clientId: aServiceId,
signal: {
type: aType,
alertPitch: aAlertPitch,
signal: aSignal
}
});
},
/**
* Wrapper to send 'cdma-info-rec-received' system message with Redirecting
* Number Info.
*/
notifyCdmaInfoRecRedirectingNumber: function(aServiceId, aType, aPlan,
aNumber, aPi, aSi, aReason) {
this.broadcastMessage("cdma-info-rec-received", {
clientId: aServiceId,
redirect: {
type: aType,
plan: aPlan,
number: aNumber,
pi: aPi,
si: aSi,
reason: aReason
}
});
},
/**
* Wrapper to send 'cdma-info-rec-received' system message with Line Control Info.
*/
notifyCdmaInfoRecLineControl: function(aServiceId, aPolarityIncluded,
aToggle, aReverse, aPowerDenial) {
this.broadcastMessage("cdma-info-rec-received", {
clientId: aServiceId,
lineControl: {
polarityIncluded: aPolarityIncluded,
toggle: aToggle,
reverse: aReverse,
powerDenial: aPowerDenial
}
});
},
/**
* Wrapper to send 'cdma-info-rec-received' system message with CLIR Info.
*/
notifyCdmaInfoRecClir: function(aServiceId, aCause) {
this.broadcastMessage("cdma-info-rec-received", {
clientId: aServiceId,
clirCause: aCause
});
},
/**
* Wrapper to send 'cdma-info-rec-received' system message with Audio Control Info.
*/
notifyCdmaInfoRecAudioControl: function(aServiceId, aUpLink, aDownLink) {
this.broadcastMessage("cdma-info-rec-received", {
clientId: aServiceId,
audioControl: {
upLink: aUpLink,
downLink: aDownLink
}
});
},
/**
* Wrapper to send 'icc-stkcommand' system message with Audio Control Info.
*/
notifyStkProactiveCommand: function(aIccId, aCommand) {
this.broadcastMessage("icc-stkcommand", {
iccId: aIccId,
command: this.createCommandMessage(aCommand)
});
}
};
this.EXPORTED_SYMBOLS = [
'RILSystemMessenger'
];

Просмотреть файл

@ -1,169 +0,0 @@
/* 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/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var RSM = {};
Cu.import("resource://gre/modules/RILSystemMessenger.jsm", RSM);
const RILSYSTEMMESSENGERHELPER_CONTRACTID =
"@mozilla.org/ril/system-messenger-helper;1";
const RILSYSTEMMESSENGERHELPER_CID =
Components.ID("{19d9a4ea-580d-11e4-8f6c-37ababfaaea9}");
XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
"@mozilla.org/system-message-internal;1",
"nsISystemMessagesInternal");
XPCOMUtils.defineLazyServiceGetter(this, "gStkCmdFactory",
"@mozilla.org/icc/stkcmdfactory;1",
"nsIStkCmdFactory");
var DEBUG = false;
function debug(s) {
dump("-@- RILSystemMessenger: " + s + "\n");
};
// Read debug setting from pref.
try {
let debugPref = Services.prefs.getBoolPref("ril.debugging.enabled");
DEBUG = DEBUG || debugPref;
} catch (e) {}
/**
* RILSystemMessengerHelper
*/
function RILSystemMessengerHelper() {
this.messenger = new RSM.RILSystemMessenger();
this.messenger.broadcastMessage = (aType, aMessage) => {
if (DEBUG) {
debug("broadcastMessage: aType: " + aType +
", aMessage: "+ JSON.stringify(aMessage));
}
gSystemMessenger.broadcastMessage(aType, aMessage);
};
this.messenger.createCommandMessage = (aStkProactiveCmd) => {
return gStkCmdFactory.createCommandMessage(aStkProactiveCmd);
};
}
RILSystemMessengerHelper.prototype = {
classID: RILSYSTEMMESSENGERHELPER_CID,
QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyMessenger,
Ci.nsISmsMessenger,
Ci.nsICellbroadcastMessenger,
Ci.nsIMobileConnectionMessenger,
Ci.nsIIccMessenger]),
/**
* RILSystemMessenger instance.
*/
messenger: null,
/**
* nsITelephonyMessenger API
*/
notifyNewCall: function() {
this.messenger.notifyNewCall();
},
notifyCallEnded: function(aServiceId, aNumber, aCdmaWaitingNumber, aEmergency,
aDuration, aOutgoing, aHangUpLocal) {
this.messenger.notifyCallEnded(aServiceId, aNumber, aCdmaWaitingNumber, aEmergency,
aDuration, aOutgoing, aHangUpLocal);
},
notifyUssdReceived: function(aServiceId, aMessage, aSessionEnded) {
this.messenger.notifyUssdReceived(aServiceId, aMessage, aSessionEnded);
},
/**
* nsISmsMessenger API
*/
notifySms: function(aNotificationType, aId, aThreadId, aIccId, aDelivery,
aDeliveryStatus, aSender, aReceiver, aBody, aMessageClass,
aTimestamp, aSentTimestamp, aDeliveryTimestamp, aRead) {
this.messenger.notifySms(aNotificationType, aId, aThreadId, aIccId, aDelivery,
aDeliveryStatus, aSender, aReceiver, aBody, aMessageClass,
aTimestamp, aSentTimestamp, aDeliveryTimestamp, aRead);
},
/**
* nsICellbroadcastMessenger API
*/
notifyCbMessageReceived: function(aServiceId, aGsmGeographicalScope, aMessageCode,
aMessageId, aLanguage, aBody, aMessageClass,
aTimestamp, aCdmaServiceCategory, aHasEtwsInfo,
aEtwsWarningType, aEtwsEmergencyUserAlert, aEtwsPopup) {
this.messenger.notifyCbMessageReceived(aServiceId, aGsmGeographicalScope, aMessageCode,
aMessageId, aLanguage, aBody, aMessageClass,
aTimestamp, aCdmaServiceCategory, aHasEtwsInfo,
aEtwsWarningType, aEtwsEmergencyUserAlert, aEtwsPopup);
},
/**
* nsIMobileConnectionMessenger API
*/
notifyCdmaInfoRecDisplay: function(aServiceId, aDisplay) {
this.messenger.notifyCdmaInfoRecDisplay(aServiceId, aDisplay);
},
notifyCdmaInfoRecCalledPartyNumber: function(aServiceId, aType, aPlan,
aNumber, aPi, aSi) {
this.messenger.notifyCdmaInfoRecCalledPartyNumber(aServiceId, aType, aPlan,
aNumber, aPi, aSi);
},
notifyCdmaInfoRecCallingPartyNumber: function(aServiceId, aType, aPlan,
aNumber, aPi, aSi) {
this.messenger.notifyCdmaInfoRecCallingPartyNumber(aServiceId, aType, aPlan,
aNumber, aPi, aSi);
},
notifyCdmaInfoRecConnectedPartyNumber: function(aServiceId, aType, aPlan,
aNumber, aPi, aSi) {
this.messenger.notifyCdmaInfoRecConnectedPartyNumber(aServiceId, aType, aPlan,
aNumber, aPi, aSi);
},
notifyCdmaInfoRecSignal: function(aServiceId, aType, aAlertPitch, aSignal) {
this.messenger.notifyCdmaInfoRecSignal(aServiceId, aType, aAlertPitch, aSignal);
},
notifyCdmaInfoRecRedirectingNumber: function(aServiceId, aType, aPlan,
aNumber, aPi, aSi, aReason) {
this.messenger.notifyCdmaInfoRecRedirectingNumber(aServiceId, aType, aPlan,
aNumber, aPi, aSi, aReason);
},
notifyCdmaInfoRecLineControl: function(aServiceId, aPolarityIncluded,
aToggle, aReverse, aPowerDenial) {
this.messenger.notifyCdmaInfoRecLineControl(aServiceId, aPolarityIncluded,
aToggle, aReverse, aPowerDenial);
},
notifyCdmaInfoRecClir: function(aServiceId, aCause) {
this.messenger.notifyCdmaInfoRecClir(aServiceId, aCause);
},
notifyCdmaInfoRecAudioControl: function(aServiceId, aUpLink, aDownLink) {
this.messenger.notifyCdmaInfoRecAudioControl(aServiceId, aUpLink, aDownLink);
},
/**
* nsIIccMessenger API
*/
notifyStkProactiveCommand: function(aIccId, aCommand) {
this.messenger.notifyStkProactiveCommand(aIccId, aCommand);
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILSystemMessengerHelper]);

Просмотреть файл

@ -1,6 +0,0 @@
# 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/.
component {19d9a4ea-580d-11e4-8f6c-37ababfaaea9} RILSystemMessengerHelper.js
contract @mozilla.org/ril/system-messenger-helper;1 {19d9a4ea-580d-11e4-8f6c-37ababfaaea9}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,18 +0,0 @@
# Copyright 2012 Mozilla Foundation and Mozilla contributors
#
# 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.
# RadioInterfaceLayer.js
component {2d831c8d-6017-435b-a80c-e5d422810cea} RadioInterfaceLayer.js
contract @mozilla.org/ril;1 {2d831c8d-6017-435b-a80c-e5d422810cea}
category profile-after-change RadioInterfaceLayer @mozilla.org/ril;1

Просмотреть файл

@ -1,98 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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/. */
#include "SystemProperty.h"
#include <dlfcn.h>
#include <string.h>
#include "nsDebug.h"
#include "prinit.h"
namespace mozilla {
namespace system {
namespace {
typedef int (*PropertyGet)(const char*, char*, const char*);
typedef int (*PropertySet)(const char*, const char*);
static void *sLibcUtils;
static PRCallOnceType sInitLibcUtils;
static int
FakePropertyGet(const char* key, char* value, const char* default_value)
{
if(!default_value) {
value[0] = '\0';
return 0;
}
int len = strlen(default_value);
if (len >= Property::VALUE_MAX_LENGTH) {
len = Property::VALUE_MAX_LENGTH - 1;
}
memcpy(value, default_value, len);
value[len] = '\0';
return len;
}
static int
FakePropertySet(const char* key, const char* value)
{
return 0;
}
static PRStatus
InitLibcUtils()
{
sLibcUtils = dlopen("/system/lib/libcutils.so", RTLD_LAZY);
// We will fallback to the fake getter/setter when sLibcUtils is not valid.
return PR_SUCCESS;
}
static void*
GetLibcUtils()
{
PR_CallOnce(&sInitLibcUtils, InitLibcUtils);
return sLibcUtils;
}
} // anonymous namespace
/*static*/ int
Property::Get(const char* key, char* value, const char* default_value)
{
void *libcutils = GetLibcUtils();
if (libcutils) {
PropertyGet getter = (PropertyGet) dlsym(libcutils, "property_get");
if (getter) {
return getter(key, value, default_value);
}
NS_WARNING("Failed to get property_get() from libcutils!");
}
NS_WARNING("Fallback to the FakePropertyGet()");
return FakePropertyGet(key, value, default_value);
}
/*static*/ int
Property::Set(const char* key, const char* value)
{
void *libcutils = GetLibcUtils();
if (libcutils) {
PropertySet setter = (PropertySet) dlsym(libcutils, "property_set");
if (setter) {
return setter(key, value);
}
NS_WARNING("Failed to get property_set() from libcutils!");
}
NS_WARNING("Fallback to the FakePropertySet()");
return FakePropertySet(key, value);
}
} // namespace system
} // namespace mozilla

Просмотреть файл

@ -1,39 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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_Property_h
#define mozilla_system_Property_h
namespace mozilla {
namespace system {
/**
* Abstraction of property_get/property_get in libcutils from AOSP.
*/
class Property
{
public:
// Constants defined in system_properties.h from AOSP.
enum {
KEY_MAX_LENGTH = 32,
VALUE_MAX_LENGTH = 92
};
static int
Get(const char* key, char* value, const char* default_value);
static int
Set(const char* key, const char* value);
private:
Property() {}
virtual ~Property() {}
};
} // namespace system
} // namespace mozilla
#endif // mozilla_system_Property_h

Просмотреть файл

@ -1,214 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
*
* 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 "SystemWorkerManager.h"
#include "nsINetworkService.h"
#include "nsIWifi.h"
#include "nsIWorkerHolder.h"
#include "nsIXPConnect.h"
#include "jsfriendapi.h"
#include "mozilla/dom/workers/Workers.h"
#include "AutoMounter.h"
#include "TimeZoneSettingObserver.h"
#include "AudioManager.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/ipc/KeyStore.h"
#include "nsIObserverService.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "WifiWorker.h"
#include "mozilla/Services.h"
USING_WORKERS_NAMESPACE
using namespace mozilla::dom::gonk;
using namespace mozilla::ipc;
using namespace mozilla::system;
namespace {
NS_DEFINE_CID(kWifiWorkerCID, NS_WIFIWORKER_CID);
// Doesn't carry a reference, we're owned by services.
SystemWorkerManager *gInstance = nullptr;
} // namespace
SystemWorkerManager::SystemWorkerManager()
: mShutdown(false)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!gInstance, "There should only be one instance!");
}
SystemWorkerManager::~SystemWorkerManager()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!gInstance || gInstance == this,
"There should only be one instance!");
gInstance = nullptr;
}
nsresult
SystemWorkerManager::Init()
{
if (!XRE_IsParentProcess()) {
return NS_ERROR_NOT_AVAILABLE;
}
NS_ASSERTION(NS_IsMainThread(), "We can only initialize on the main thread");
NS_ASSERTION(!mShutdown, "Already shutdown!");
nsresult rv = InitWifi();
if (NS_FAILED(rv)) {
NS_WARNING("Failed to initialize WiFi Networking!");
return rv;
}
InitKeyStore();
InitAutoMounter();
InitializeTimeZoneSettingObserver();
nsCOMPtr<nsIAudioManager> audioManager =
do_GetService(NS_AUDIOMANAGER_CONTRACTID);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (!obs) {
NS_WARNING("Failed to get observer service!");
return NS_ERROR_FAILURE;
}
rv = obs->AddObserver(this, WORKERS_SHUTDOWN_TOPIC, false);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to initialize worker shutdown event!");
return rv;
}
return NS_OK;
}
void
SystemWorkerManager::Shutdown()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
mShutdown = true;
ShutdownAutoMounter();
nsCOMPtr<nsIWifi> wifi(do_QueryInterface(mWifiWorker));
if (wifi) {
wifi->Shutdown();
wifi = nullptr;
}
mWifiWorker = nullptr;
if (mKeyStore) {
mKeyStore->Shutdown();
mKeyStore = nullptr;
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->RemoveObserver(this, WORKERS_SHUTDOWN_TOPIC);
}
}
// static
already_AddRefed<SystemWorkerManager>
SystemWorkerManager::FactoryCreate()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
RefPtr<SystemWorkerManager> instance(gInstance);
if (!instance) {
instance = new SystemWorkerManager();
if (NS_FAILED(instance->Init())) {
instance->Shutdown();
return nullptr;
}
gInstance = instance;
}
return instance.forget();
}
// static
nsIInterfaceRequestor*
SystemWorkerManager::GetInterfaceRequestor()
{
return gInstance;
}
NS_IMETHODIMP
SystemWorkerManager::GetInterface(const nsIID &aIID, void **aResult)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (aIID.Equals(NS_GET_IID(nsIWifi))) {
return CallQueryInterface(mWifiWorker,
reinterpret_cast<nsIWifi**>(aResult));
}
NS_WARNING("Got nothing for the requested IID!");
return NS_ERROR_NO_INTERFACE;
}
nsresult
SystemWorkerManager::RegisterRilWorker(unsigned int aClientId,
JS::Handle<JS::Value> aWorker,
JSContext *aCx)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
SystemWorkerManager::InitWifi()
{
nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kWifiWorkerCID);
NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
mWifiWorker = worker;
return NS_OK;
}
nsresult
SystemWorkerManager::InitKeyStore()
{
mKeyStore = new KeyStore();
return NS_OK;
}
NS_IMPL_ISUPPORTS(SystemWorkerManager,
nsIObserver,
nsIInterfaceRequestor,
nsISystemWorkerManager)
NS_IMETHODIMP
SystemWorkerManager::Observe(nsISupports *aSubject, const char *aTopic,
const char16_t *aData)
{
if (!strcmp(aTopic, WORKERS_SHUTDOWN_TOPIC)) {
Shutdown();
}
return NS_OK;
}

Просмотреть файл

@ -1,75 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
*
* 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.
*/
#ifndef mozilla_dom_system_b2g_systemworkermanager_h__
#define mozilla_dom_system_b2g_systemworkermanager_h__
#include "nsIInterfaceRequestor.h"
#include "nsISystemWorkerManager.h"
#include "nsIObserver.h"
#include "nsCOMPtr.h"
#include "nsXULAppAPI.h" // For XRE_GetProcessType
class nsIWorkerHolder;
namespace mozilla {
namespace ipc {
class KeyStore;
}
namespace dom {
namespace gonk {
class SystemWorkerManager final : public nsIObserver,
public nsIInterfaceRequestor,
public nsISystemWorkerManager
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSISYSTEMWORKERMANAGER
nsresult Init();
void Shutdown();
static already_AddRefed<SystemWorkerManager>
FactoryCreate();
static nsIInterfaceRequestor*
GetInterfaceRequestor();
private:
SystemWorkerManager();
~SystemWorkerManager();
nsresult InitWifi();
nsresult InitKeyStore();
nsCOMPtr<nsIWorkerHolder> mWifiWorker;
RefPtr<mozilla::ipc::KeyStore> mKeyStore;
bool mShutdown;
};
}
}
}
#endif // mozilla_dom_system_b2g_systemworkermanager_h__

Просмотреть файл

@ -1,891 +0,0 @@
/* 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/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/systemlibs.js");
const TETHERINGSERVICE_CONTRACTID = "@mozilla.org/tethering/service;1";
const TETHERINGSERVICE_CID =
Components.ID("{527a4121-ee5a-4651-be9c-f46f59cf7c01}");
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
"@mozilla.org/network/manager;1",
"nsINetworkManager");
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService",
"@mozilla.org/network/service;1",
"nsINetworkService");
XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
"@mozilla.org/settingsService;1",
"nsISettingsService");
XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
"nsIMobileConnectionService");
XPCOMUtils.defineLazyGetter(this, "gRil", function() {
try {
return Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
} catch (e) {}
return null;
});
const TOPIC_MOZSETTINGS_CHANGED = "mozsettings-changed";
const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed";
const TOPIC_PREF_CHANGED = "nsPref:changed";
const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown";
const PREF_MANAGE_OFFLINE_STATUS = "network.gonk.manage-offline-status";
const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled";
const POSSIBLE_USB_INTERFACE_NAME = "rndis0,usb0";
const DEFAULT_USB_INTERFACE_NAME = "rndis0";
const DEFAULT_3G_INTERFACE_NAME = "rmnet0";
const DEFAULT_WIFI_INTERFACE_NAME = "wlan0";
// The kernel's proc entry for network lists.
const KERNEL_NETWORK_ENTRY = "/sys/class/net";
const TETHERING_TYPE_WIFI = "WiFi";
const TETHERING_TYPE_USB = "USB";
const WIFI_FIRMWARE_AP = "AP";
const WIFI_FIRMWARE_STATION = "STA";
const WIFI_SECURITY_TYPE_NONE = "open";
const WIFI_SECURITY_TYPE_WPA_PSK = "wpa-psk";
const WIFI_SECURITY_TYPE_WPA2_PSK = "wpa2-psk";
const WIFI_CTRL_INTERFACE = "wl0.1";
const NETWORK_INTERFACE_UP = "up";
const NETWORK_INTERFACE_DOWN = "down";
const TETHERING_STATE_ONGOING = "ongoing";
const TETHERING_STATE_IDLE = "idle";
const TETHERING_STATE_ACTIVE = "active";
// Settings DB path for USB tethering.
const SETTINGS_USB_ENABLED = "tethering.usb.enabled";
const SETTINGS_USB_IP = "tethering.usb.ip";
const SETTINGS_USB_PREFIX = "tethering.usb.prefix";
const SETTINGS_USB_DHCPSERVER_STARTIP = "tethering.usb.dhcpserver.startip";
const SETTINGS_USB_DHCPSERVER_ENDIP = "tethering.usb.dhcpserver.endip";
const SETTINGS_USB_DNS1 = "tethering.usb.dns1";
const SETTINGS_USB_DNS2 = "tethering.usb.dns2";
// Settings DB path for WIFI tethering.
const SETTINGS_WIFI_DHCPSERVER_STARTIP = "tethering.wifi.dhcpserver.startip";
const SETTINGS_WIFI_DHCPSERVER_ENDIP = "tethering.wifi.dhcpserver.endip";
// Settings DB patch for dun required setting.
const SETTINGS_DUN_REQUIRED = "tethering.dun.required";
// Default value for USB tethering.
const DEFAULT_USB_IP = "192.168.0.1";
const DEFAULT_USB_PREFIX = "24";
const DEFAULT_USB_DHCPSERVER_STARTIP = "192.168.0.10";
const DEFAULT_USB_DHCPSERVER_ENDIP = "192.168.0.30";
const DEFAULT_DNS1 = "8.8.8.8";
const DEFAULT_DNS2 = "8.8.4.4";
const DEFAULT_WIFI_DHCPSERVER_STARTIP = "192.168.1.10";
const DEFAULT_WIFI_DHCPSERVER_ENDIP = "192.168.1.30";
const SETTINGS_DATA_DEFAULT_SERVICE_ID = "ril.data.defaultServiceId";
const MOBILE_DUN_CONNECT_TIMEOUT = 30000;
const MOBILE_DUN_RETRY_INTERVAL = 5000;
const MOBILE_DUN_MAX_RETRIES = 5;
var debug;
function updateDebug() {
let debugPref = false; // set default value here.
try {
debugPref = debugPref || Services.prefs.getBoolPref(PREF_NETWORK_DEBUG_ENABLED);
} catch (e) {}
if (debugPref) {
debug = function(s) {
dump("-*- TetheringService: " + s + "\n");
};
} else {
debug = function(s) {};
}
}
updateDebug();
function TetheringService() {
Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN);
Services.obs.addObserver(this, TOPIC_MOZSETTINGS_CHANGED);
Services.obs.addObserver(this, TOPIC_CONNECTION_STATE_CHANGED);
Services.prefs.addObserver(PREF_NETWORK_DEBUG_ENABLED, this);
Services.prefs.addObserver(PREF_MANAGE_OFFLINE_STATUS, this);
try {
this._manageOfflineStatus =
Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS);
} catch(ex) {
// Ignore.
}
this._dataDefaultServiceId = 0;
// Possible usb tethering interfaces for different gonk platform.
this.possibleInterface = POSSIBLE_USB_INTERFACE_NAME.split(",");
// Default values for internal and external interfaces.
this._tetheringInterface = {};
this._tetheringInterface[TETHERING_TYPE_USB] = {
externalInterface: DEFAULT_3G_INTERFACE_NAME,
internalInterface: DEFAULT_USB_INTERFACE_NAME
};
this._tetheringInterface[TETHERING_TYPE_WIFI] = {
externalInterface: DEFAULT_3G_INTERFACE_NAME,
internalInterface: DEFAULT_WIFI_INTERFACE_NAME
};
this.tetheringSettings = {};
this.initTetheringSettings();
let settingsLock = gSettingsService.createLock();
// Read the default service id for data call.
settingsLock.get(SETTINGS_DATA_DEFAULT_SERVICE_ID, this);
// Read usb tethering data from settings DB.
settingsLock.get(SETTINGS_USB_IP, this);
settingsLock.get(SETTINGS_USB_PREFIX, this);
settingsLock.get(SETTINGS_USB_DHCPSERVER_STARTIP, this);
settingsLock.get(SETTINGS_USB_DHCPSERVER_ENDIP, this);
settingsLock.get(SETTINGS_USB_DNS1, this);
settingsLock.get(SETTINGS_USB_DNS2, this);
settingsLock.get(SETTINGS_USB_ENABLED, this);
// Read wifi tethering data from settings DB.
settingsLock.get(SETTINGS_WIFI_DHCPSERVER_STARTIP, this);
settingsLock.get(SETTINGS_WIFI_DHCPSERVER_ENDIP, this);
this._usbTetheringSettingsToRead = [SETTINGS_USB_IP,
SETTINGS_USB_PREFIX,
SETTINGS_USB_DHCPSERVER_STARTIP,
SETTINGS_USB_DHCPSERVER_ENDIP,
SETTINGS_USB_DNS1,
SETTINGS_USB_DNS2,
SETTINGS_USB_ENABLED,
SETTINGS_WIFI_DHCPSERVER_STARTIP,
SETTINGS_WIFI_DHCPSERVER_ENDIP];
this.wantConnectionEvent = null;
this.dunConnectTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.dunRetryTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._pendingTetheringRequests = [];
}
TetheringService.prototype = {
classID: TETHERINGSERVICE_CID,
classInfo: XPCOMUtils.generateCI({classID: TETHERINGSERVICE_CID,
contractID: TETHERINGSERVICE_CONTRACTID,
classDescription: "Tethering Service",
interfaces: [Ci.nsITetheringService]}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsITetheringService,
Ci.nsISupportsWeakReference,
Ci.nsIObserver,
Ci.nsISettingsServiceCallback]),
// Flag to record the default client id for data call.
_dataDefaultServiceId: null,
// Number of usb tehering requests to be processed.
_usbTetheringRequestCount: 0,
// Usb tethering state.
_usbTetheringAction: TETHERING_STATE_IDLE,
// Tethering settings.
tetheringSettings: null,
// Tethering settings need to be read from settings DB.
_usbTetheringSettingsToRead: null,
// Previous usb tethering enabled state.
_oldUsbTetheringEnabledState: null,
// External and internal interface name.
_tetheringInterface: null,
// Dun connection timer.
dunConnectTimer: null,
// Dun connection retry times.
dunRetryTimes: 0,
// Dun retry timer.
dunRetryTimer: null,
// Pending tethering request to handle after dun is connected.
_pendingTetheringRequests: null,
// Flag to indicate wether wifi tethering is being processed.
_wifiTetheringRequestOngoing: false,
// Arguments for pending wifi tethering request.
_pendingWifiTetheringRequestArgs: null,
// The state of tethering.
state: Ci.nsITetheringService.TETHERING_STATE_INACTIVE,
// Flag to check if we can modify the Services.io.offline.
_manageOfflineStatus: true,
// nsIObserver
observe: function(aSubject, aTopic, aData) {
let network;
switch(aTopic) {
case TOPIC_PREF_CHANGED:
if (aData === PREF_NETWORK_DEBUG_ENABLED) {
updateDebug();
}
break;
case TOPIC_MOZSETTINGS_CHANGED:
if ("wrappedJSObject" in aSubject) {
aSubject = aSubject.wrappedJSObject;
}
this.handle(aSubject.key, aSubject.value);
break;
case TOPIC_CONNECTION_STATE_CHANGED:
network = aSubject.QueryInterface(Ci.nsINetworkInfo);
debug("Network " + network.type + "/" + network.name +
" changed state to " + network.state);
this.onConnectionChanged(network);
break;
case TOPIC_XPCOM_SHUTDOWN:
Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
Services.obs.removeObserver(this, TOPIC_MOZSETTINGS_CHANGED);
Services.obs.removeObserver(this, TOPIC_CONNECTION_STATE_CHANGED);
Services.prefs.removeObserver(PREF_NETWORK_DEBUG_ENABLED, this);
Services.prefs.removeObserver(PREF_MANAGE_OFFLINE_STATUS, this);
this.dunConnectTimer.cancel();
this.dunRetryTimer.cancel();
break;
case PREF_MANAGE_OFFLINE_STATUS:
try {
this._manageOfflineStatus =
Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS);
} catch(ex) {
// Ignore.
}
break;
}
},
// nsISettingsServiceCallback
handle: function(aName, aResult) {
switch(aName) {
case SETTINGS_DATA_DEFAULT_SERVICE_ID:
this._dataDefaultServiceId = aResult || 0;
debug("'_dataDefaultServiceId' is now " + this._dataDefaultServiceId);
break;
case SETTINGS_USB_ENABLED:
this._oldUsbTetheringEnabledState = this.tetheringSettings[SETTINGS_USB_ENABLED];
case SETTINGS_USB_IP:
case SETTINGS_USB_PREFIX:
case SETTINGS_USB_DHCPSERVER_STARTIP:
case SETTINGS_USB_DHCPSERVER_ENDIP:
case SETTINGS_USB_DNS1:
case SETTINGS_USB_DNS2:
case SETTINGS_WIFI_DHCPSERVER_STARTIP:
case SETTINGS_WIFI_DHCPSERVER_ENDIP:
if (aResult !== null) {
this.tetheringSettings[aName] = aResult;
}
debug("'" + aName + "'" + " is now " + this.tetheringSettings[aName]);
let index = this._usbTetheringSettingsToRead.indexOf(aName);
if (index != -1) {
this._usbTetheringSettingsToRead.splice(index, 1);
}
if (this._usbTetheringSettingsToRead.length) {
debug("We haven't read completely the usb Tethering data from settings db.");
break;
}
if (this._oldUsbTetheringEnabledState === this.tetheringSettings[SETTINGS_USB_ENABLED]) {
debug("No changes for SETTINGS_USB_ENABLED flag. Nothing to do.");
this.handlePendingWifiTetheringRequest();
break;
}
this._usbTetheringRequestCount++;
if (this._usbTetheringRequestCount === 1) {
if (this._wifiTetheringRequestOngoing) {
debug('USB tethering request is blocked by ongoing wifi tethering request.');
} else {
this.handleLastUsbTetheringRequest();
}
}
break;
};
},
handleError: function(aErrorMessage) {
debug("There was an error while reading Tethering settings.");
this.tetheringSettings = {};
this.tetheringSettings[SETTINGS_USB_ENABLED] = false;
},
initTetheringSettings: function() {
this.tetheringSettings[SETTINGS_USB_ENABLED] = false;
this.tetheringSettings[SETTINGS_USB_IP] = DEFAULT_USB_IP;
this.tetheringSettings[SETTINGS_USB_PREFIX] = DEFAULT_USB_PREFIX;
this.tetheringSettings[SETTINGS_USB_DHCPSERVER_STARTIP] = DEFAULT_USB_DHCPSERVER_STARTIP;
this.tetheringSettings[SETTINGS_USB_DHCPSERVER_ENDIP] = DEFAULT_USB_DHCPSERVER_ENDIP;
this.tetheringSettings[SETTINGS_USB_DNS1] = DEFAULT_DNS1;
this.tetheringSettings[SETTINGS_USB_DNS2] = DEFAULT_DNS2;
this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_STARTIP] = DEFAULT_WIFI_DHCPSERVER_STARTIP;
this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_ENDIP] = DEFAULT_WIFI_DHCPSERVER_ENDIP;
this.tetheringSettings[SETTINGS_DUN_REQUIRED] =
libcutils.property_get("ro.tethering.dun_required") === "1";
},
getNetworkInfo: function(aType, aServiceId) {
for (let networkId in gNetworkManager.allNetworkInfo) {
let networkInfo = gNetworkManager.allNetworkInfo[networkId];
if (networkInfo.type == aType) {
try {
if (networkInfo instanceof Ci.nsIRilNetworkInfo) {
let rilNetwork = networkInfo.QueryInterface(Ci.nsIRilNetworkInfo);
if (rilNetwork.serviceId != aServiceId) {
continue;
}
}
} catch (e) {}
return networkInfo;
}
}
return null;
},
handleLastUsbTetheringRequest: function() {
debug('handleLastUsbTetheringRequest... ' + this._usbTetheringRequestCount);
if (this._usbTetheringRequestCount === 0) {
if (this.wantConnectionEvent) {
if (this.tetheringSettings[SETTINGS_USB_ENABLED]) {
this.wantConnectionEvent.call(this);
}
this.wantConnectionEvent = null;
}
this.handlePendingWifiTetheringRequest();
return;
}
// Cancel the accumlated count to 1 since we only care about the
// last state.
this._usbTetheringRequestCount = 1;
this.handleUSBTetheringToggle(this.tetheringSettings[SETTINGS_USB_ENABLED]);
this.wantConnectionEvent = null;
},
handlePendingWifiTetheringRequest: function() {
if (this._pendingWifiTetheringRequestArgs) {
this.setWifiTethering.apply(this, this._pendingWifiTetheringRequestArgs);
this._pendingWifiTetheringRequestArgs = null;
}
},
/**
* Callback when dun connection fails to connect within timeout.
*/
onDunConnectTimerTimeout: function() {
while (this._pendingTetheringRequests.length > 0) {
debug("onDunConnectTimerTimeout: callback without network info.");
let callback = this._pendingTetheringRequests.shift();
if (typeof callback === 'function') {
callback();
}
}
},
setupDunConnection: function() {
this.dunRetryTimer.cancel();
let connection =
gMobileConnectionService.getItemByServiceId(this._dataDefaultServiceId);
let data = connection && connection.data;
if (data && data.state === "registered") {
let ril = gRil.getRadioInterface(this._dataDefaultServiceId);
this.dunRetryTimes = 0;
ril.setupDataCallByType(Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN);
this.dunConnectTimer.cancel();
this.dunConnectTimer.
initWithCallback(this.onDunConnectTimerTimeout.bind(this),
MOBILE_DUN_CONNECT_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
return;
}
if (this.dunRetryTimes++ >= this.MOBILE_DUN_MAX_RETRIES) {
debug("setupDunConnection: max retries reached.");
this.dunRetryTimes = 0;
// same as dun connect timeout.
this.onDunConnectTimerTimeout();
return;
}
debug("Data not ready, retry dun after " + MOBILE_DUN_RETRY_INTERVAL + " ms.");
this.dunRetryTimer.
initWithCallback(this.setupDunConnection.bind(this),
MOBILE_DUN_RETRY_INTERVAL, Ci.nsITimer.TYPE_ONE_SHOT);
},
_dunActiveUsers: 0,
handleDunConnection: function(aEnable, aCallback) {
debug("handleDunConnection: " + aEnable);
let dun = this.getNetworkInfo(
Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN, this._dataDefaultServiceId);
if (!aEnable) {
this._dunActiveUsers--;
if (this._dunActiveUsers > 0) {
debug("Dun still needed by others, do not disconnect.")
return;
}
this.dunRetryTimes = 0;
this.dunRetryTimer.cancel();
this.dunConnectTimer.cancel();
this._pendingTetheringRequests = [];
if (dun && (dun.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED)) {
gRil.getRadioInterface(this._dataDefaultServiceId)
.deactivateDataCallByType(Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN);
}
return;
}
this._dunActiveUsers++;
if (!dun || (dun.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED)) {
debug("DUN data call inactive, setup dun data call!")
this._pendingTetheringRequests.push(aCallback);
this.dunRetryTimes = 0;
this.setupDunConnection();
return;
}
this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = dun.name;
aCallback(dun);
},
handleUSBTetheringToggle: function(aEnable) {
debug("handleUSBTetheringToggle: " + aEnable);
if (aEnable &&
(this._usbTetheringAction === TETHERING_STATE_ONGOING ||
this._usbTetheringAction === TETHERING_STATE_ACTIVE)) {
debug("Usb tethering already connecting/connected.");
this._usbTetheringRequestCount = 0;
this.handlePendingWifiTetheringRequest();
return;
}
if (!aEnable &&
this._usbTetheringAction === TETHERING_STATE_IDLE) {
debug("Usb tethering already disconnected.");
this._usbTetheringRequestCount = 0;
this.handlePendingWifiTetheringRequest();
return;
}
if (!aEnable) {
this.tetheringSettings[SETTINGS_USB_ENABLED] = false;
gNetworkService.enableUsbRndis(false, this.enableUsbRndisResult.bind(this));
return;
}
this.tetheringSettings[SETTINGS_USB_ENABLED] = true;
this._usbTetheringAction = TETHERING_STATE_ONGOING;
if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) {
this.handleDunConnection(true, (aNetworkInfo) => {
if (!aNetworkInfo){
this.usbTetheringResultReport(aEnable, "Dun connection failed");
return;
}
this._tetheringInterface[TETHERING_TYPE_USB].externalInterface =
aNetworkInfo.name;
gNetworkService.enableUsbRndis(true, this.enableUsbRndisResult.bind(this));
});
return;
}
if (gNetworkManager.activeNetworkInfo) {
this._tetheringInterface[TETHERING_TYPE_USB].externalInterface =
gNetworkManager.activeNetworkInfo.name;
} else {
let mobile = this.getNetworkInfo(
Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE, this._dataDefaultServiceId);
if (mobile && mobile.name) {
this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = mobile.name;
}
}
gNetworkService.enableUsbRndis(true, this.enableUsbRndisResult.bind(this));
},
getUSBTetheringParameters: function(aEnable, aTetheringInterface) {
let interfaceIp = this.tetheringSettings[SETTINGS_USB_IP];
let prefix = this.tetheringSettings[SETTINGS_USB_PREFIX];
let wifiDhcpStartIp = this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_STARTIP];
let wifiDhcpEndIp = this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_ENDIP];
let usbDhcpStartIp = this.tetheringSettings[SETTINGS_USB_DHCPSERVER_STARTIP];
let usbDhcpEndIp = this.tetheringSettings[SETTINGS_USB_DHCPSERVER_ENDIP];
let dns1 = this.tetheringSettings[SETTINGS_USB_DNS1];
let dns2 = this.tetheringSettings[SETTINGS_USB_DNS2];
let internalInterface = aTetheringInterface.internalInterface;
let externalInterface = aTetheringInterface.externalInterface;
// Using the default values here until application support these settings.
if (interfaceIp == "" || prefix == "" ||
wifiDhcpStartIp == "" || wifiDhcpEndIp == "" ||
usbDhcpStartIp == "" || usbDhcpEndIp == "") {
debug("Invalid subnet information.");
return null;
}
return {
ifname: internalInterface,
ip: interfaceIp,
prefix: prefix,
wifiStartIp: wifiDhcpStartIp,
wifiEndIp: wifiDhcpEndIp,
usbStartIp: usbDhcpStartIp,
usbEndIp: usbDhcpEndIp,
dns1: dns1,
dns2: dns2,
internalIfname: internalInterface,
externalIfname: externalInterface,
enable: aEnable,
link: aEnable ? NETWORK_INTERFACE_UP : NETWORK_INTERFACE_DOWN
};
},
notifyError: function(aResetSettings, aCallback, aMsg) {
if (aResetSettings) {
let settingsLock = gSettingsService.createLock();
// Disable wifi tethering with a useful error message for the user.
settingsLock.set("tethering.wifi.enabled", false, null, aMsg);
}
debug("setWifiTethering: " + (aMsg ? aMsg : "success"));
if (aCallback) {
// Callback asynchronously to avoid netsted toggling.
Services.tm.dispatchToMainThread(() => {
aCallback.wifiTetheringEnabledChange(aMsg);
});
}
},
enableWifiTethering: function(aEnable, aConfig, aCallback) {
// Fill in config's required fields.
aConfig.ifname = this._tetheringInterface[TETHERING_TYPE_WIFI].internalInterface;
aConfig.internalIfname = this._tetheringInterface[TETHERING_TYPE_WIFI].internalInterface;
aConfig.externalIfname = this._tetheringInterface[TETHERING_TYPE_WIFI].externalInterface;
this._wifiTetheringRequestOngoing = true;
gNetworkService.setWifiTethering(aEnable, aConfig, (aError) => {
// Change the tethering state to WIFI if there is no error.
if (aEnable && !aError) {
this.state = Ci.nsITetheringService.TETHERING_STATE_WIFI;
} else {
// If wifi thethering is disable, or any error happens,
// then consider the following statements.
// Check whether the state is USB now or not. If no then just change
// it to INACTIVE, if yes then just keep it.
// It means that don't let the disable or error of WIFI affect
// the original active state.
if (this.state != Ci.nsITetheringService.TETHERING_STATE_USB) {
this.state = Ci.nsITetheringService.TETHERING_STATE_INACTIVE;
}
// Disconnect dun on error or when wifi tethering is disabled.
if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) {
this.handleDunConnection(false);
}
}
if (this._manageOfflineStatus) {
Services.io.offline = !this.isAnyConnected() &&
(this.state ===
Ci.nsITetheringService.TETHERING_STATE_INACTIVE);
}
let resetSettings = aError;
debug('gNetworkService.setWifiTethering finished');
this.notifyError(resetSettings, aCallback, aError);
this._wifiTetheringRequestOngoing = false;
if (this._usbTetheringRequestCount > 0) {
debug('Perform pending USB tethering requests.');
this.handleLastUsbTetheringRequest();
}
});
},
// Enable/disable WiFi tethering by sending commands to netd.
setWifiTethering: function(aEnable, aInterfaceName, aConfig, aCallback) {
debug("setWifiTethering: " + aEnable);
if (!aInterfaceName) {
this.notifyError(true, aCallback, "invalid network interface name");
return;
}
if (!aConfig) {
this.notifyError(true, aCallback, "invalid configuration");
return;
}
if (this._usbTetheringRequestCount > 0) {
// If there's still pending usb tethering request, save
// the request params and redo |setWifiTethering| on
// usb tethering task complete.
debug('USB tethering request is being processed. Queue this wifi tethering request.');
this._pendingWifiTetheringRequestArgs = Array.prototype.slice.call(arguments);
debug('Pending args: ' + JSON.stringify(this._pendingWifiTetheringRequestArgs));
return;
}
// Re-check again, test cases set this property later.
this.tetheringSettings[SETTINGS_DUN_REQUIRED] =
libcutils.property_get("ro.tethering.dun_required") === "1";
if (!aEnable) {
this.enableWifiTethering(false, aConfig, aCallback);
return;
}
this._tetheringInterface[TETHERING_TYPE_WIFI].internalInterface =
aInterfaceName;
if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) {
this.handleDunConnection(true, (aNetworkInfo) => {
if (!aNetworkInfo) {
this.notifyError(true, aCallback, "Dun connection failed");
return;
}
this._tetheringInterface[TETHERING_TYPE_WIFI].externalInterface =
aNetworkInfo.name;
this.enableWifiTethering(true, aConfig, aCallback);
});
return;
}
let mobile = this.getNetworkInfo(
Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE, this._dataDefaultServiceId);
// Update the real interface name
if (mobile && mobile.name) {
this._tetheringInterface[TETHERING_TYPE_WIFI].externalInterface = mobile.name;
}
this.enableWifiTethering(true, aConfig, aCallback);
},
// Enable/disable USB tethering by sending commands to netd.
setUSBTethering: function(aEnable, aTetheringInterface, aCallback) {
let params = this.getUSBTetheringParameters(aEnable, aTetheringInterface);
if (params === null) {
gNetworkService.enableUsbRndis(false, function() {
this.usbTetheringResultReport(aEnable, "Invalid parameters");
});
return;
}
gNetworkService.setUSBTethering(aEnable, params, aCallback);
},
getUsbInterface: function() {
// Find the rndis interface.
for (let i = 0; i < this.possibleInterface.length; i++) {
try {
let file = new FileUtils.File(KERNEL_NETWORK_ENTRY + "/" +
this.possibleInterface[i]);
if (file.exists()) {
return this.possibleInterface[i];
}
} catch (e) {
debug("Not " + this.possibleInterface[i] + " interface.");
}
}
debug("Can't find rndis interface in possible lists.");
return DEFAULT_USB_INTERFACE_NAME;
},
enableUsbRndisResult: function(aSuccess, aEnable) {
if (aSuccess) {
// If enable is false, don't find usb interface cause it is already down,
// just use the internal interface in settings.
if (aEnable) {
this._tetheringInterface[TETHERING_TYPE_USB].internalInterface =
this.getUsbInterface();
}
this.setUSBTethering(aEnable,
this._tetheringInterface[TETHERING_TYPE_USB],
this.usbTetheringResultReport.bind(this, aEnable));
} else {
this.usbTetheringResultReport(aEnable, "enableUsbRndisResult failure");
throw new Error("failed to set USB Function to adb");
}
},
usbTetheringResultReport: function(aEnable, aError) {
this._usbTetheringRequestCount--;
let settingsLock = gSettingsService.createLock();
debug('usbTetheringResultReport callback. enable: ' + aEnable +
', error: ' + aError);
// Disable tethering settings when fail to enable it.
if (aError) {
this.tetheringSettings[SETTINGS_USB_ENABLED] = false;
settingsLock.set("tethering.usb.enabled", false, null);
// Skip others request when we found an error.
this._usbTetheringRequestCount = 0;
this._usbTetheringAction = TETHERING_STATE_IDLE;
// If the thethering state is WIFI now, then just keep it,
// if not, just change the state to INACTIVE.
// It means that don't let the error of USB affect the original active state.
if (this.state != Ci.nsITetheringService.TETHERING_STATE_WIFI) {
this.state = Ci.nsITetheringService.TETHERING_STATE_INACTIVE;
}
if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) {
this.handleDunConnection(false);
}
} else {
if (aEnable) {
this._usbTetheringAction = TETHERING_STATE_ACTIVE;
this.state = Ci.nsITetheringService.TETHERING_STATE_USB;
} else {
this._usbTetheringAction = TETHERING_STATE_IDLE;
// If the state is now WIFI, don't let the disable of USB affect it.
if (this.state != Ci.nsITetheringService.TETHERING_STATE_WIFI) {
this.state = Ci.nsITetheringService.TETHERING_STATE_INACTIVE;
}
if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) {
this.handleDunConnection(false);
}
}
if (this._manageOfflineStatus) {
Services.io.offline = !this.isAnyConnected() &&
(this.state ===
Ci.nsITetheringService.TETHERING_STATE_INACTIVE);
}
this.handleLastUsbTetheringRequest();
}
},
onConnectionChangedReport: function(aSuccess, aExternalIfname) {
debug("onConnectionChangedReport result: success " + aSuccess);
if (aSuccess) {
// Update the external interface.
this._tetheringInterface[TETHERING_TYPE_USB].externalInterface =
aExternalIfname;
debug("Change the interface name to " + aExternalIfname);
}
},
onConnectionChanged: function(aNetworkInfo) {
if (aNetworkInfo.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) {
debug("We are only interested in CONNECTED event");
return;
}
if (this.tetheringSettings[SETTINGS_DUN_REQUIRED] &&
aNetworkInfo.type === Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN) {
this.dunConnectTimer.cancel();
debug("DUN data call connected, process callbacks.");
while (this._pendingTetheringRequests.length > 0) {
let callback = this._pendingTetheringRequests.shift();
if (typeof callback === 'function') {
callback(aNetworkInfo);
}
}
return;
}
if (!this.tetheringSettings[SETTINGS_USB_ENABLED]) {
debug("Usb tethering settings is not enabled");
return;
}
if (this.tetheringSettings[SETTINGS_DUN_REQUIRED] &&
aNetworkInfo.type === Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN &&
this._tetheringInterface[TETHERING_TYPE_USB].externalInterface ===
aNetworkInfo.name) {
debug("Dun required and dun interface is the same");
return;
}
if (this._tetheringInterface[TETHERING_TYPE_USB].externalInterface ===
gNetworkManager.activeNetworkInfo.name) {
debug("The active interface is the same");
return;
}
let previous = {
internalIfname: this._tetheringInterface[TETHERING_TYPE_USB].internalInterface,
externalIfname: this._tetheringInterface[TETHERING_TYPE_USB].externalInterface
};
let current = {
internalIfname: this._tetheringInterface[TETHERING_TYPE_USB].internalInterface,
externalIfname: aNetworkInfo.name
};
let callback = (() => {
// Update external network interface.
debug("Update upstream interface to " + aNetworkInfo.name);
gNetworkService.updateUpStream(previous, current,
this.onConnectionChangedReport.bind(this));
});
if (this._usbTetheringAction === TETHERING_STATE_ONGOING) {
debug("Postpone the event and handle it when state is idle.");
this.wantConnectionEvent = callback;
return;
}
this.wantConnectionEvent = null;
callback.call(this);
},
isAnyConnected: function() {
let allNetworkInfo = gNetworkManager.allNetworkInfo;
for (let networkId in allNetworkInfo) {
if (allNetworkInfo.hasOwnProperty(networkId) &&
allNetworkInfo[networkId].state === Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) {
return true;
}
}
return false;
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TetheringService]);

Просмотреть файл

@ -1,4 +0,0 @@
# TetheringService.js
component {527a4121-ee5a-4651-be9c-f46f59cf7c01} TetheringService.js
contract @mozilla.org/tethering/service;1 {527a4121-ee5a-4651-be9c-f46f59cf7c01}
category profile-after-change TetheringService @mozilla.org/tethering/service;1

Просмотреть файл

@ -1,239 +0,0 @@
/* 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/. */
#include "base/message_loop.h"
#include "jsapi.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/Attributes.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Hal.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsISettingsService.h"
#include "nsJSUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "TimeZoneSettingObserver.h"
#include "xpcpublic.h"
#include "nsContentUtils.h"
#include "nsPrintfCString.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/SettingChangeNotificationBinding.h"
#undef LOG
#undef ERR
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Time Zone Setting" , ## args)
#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "Time Zone Setting" , ## args)
#define TIME_TIMEZONE "time.timezone"
#define MOZSETTINGS_CHANGED "mozsettings-changed"
using namespace mozilla;
using namespace mozilla::dom;
namespace {
class TimeZoneSettingObserver : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
TimeZoneSettingObserver();
static nsresult SetTimeZone(const JS::Value &aValue, JSContext *aContext);
protected:
virtual ~TimeZoneSettingObserver();
};
class TimeZoneSettingCb final : public nsISettingsServiceCallback
{
public:
NS_DECL_ISUPPORTS
TimeZoneSettingCb() {}
NS_IMETHOD Handle(const nsAString &aName, JS::Handle<JS::Value> aResult) {
JSContext *cx = nsContentUtils::GetCurrentJSContext();
NS_ENSURE_TRUE(cx, NS_OK);
// If we don't have time.timezone value in the settings, we need
// to initialize the settings based on the current system timezone
// to make settings consistent with system. This usually happens
// at the very first boot. After that, settings must have a value.
if (aResult.isNull()) {
// Get the current system time zone offset. Note that we need to
// convert the value to a UTC representation in the format of
// "UTC{+,-}hh:mm", so that the Gaia end can know how to interpret.
// E.g., -480 is "UTC+08:00"; 630 is "UTC-10:30".
int32_t timeZoneOffset = hal::GetTimezoneOffset();
nsPrintfCString curTimeZone("UTC%+03d:%02d",
-timeZoneOffset / 60,
abs(timeZoneOffset) % 60);
// Convert it to a JS string.
NS_ConvertUTF8toUTF16 utf16Str(curTimeZone);
JS::Rooted<JSString*> jsStr(cx, JS_NewUCStringCopyN(cx,
utf16Str.get(),
utf16Str.Length()));
if (!jsStr) {
return NS_ERROR_OUT_OF_MEMORY;
}
// Set the settings based on the current system timezone.
nsCOMPtr<nsISettingsServiceLock> lock;
nsCOMPtr<nsISettingsService> settingsService =
do_GetService("@mozilla.org/settingsService;1");
if (!settingsService) {
ERR("Failed to get settingsLock service!");
return NS_OK;
}
settingsService->CreateLock(nullptr, getter_AddRefs(lock));
JS::Rooted<JS::Value> value(cx, JS::StringValue(jsStr));
lock->Set(TIME_TIMEZONE, value, nullptr, nullptr);
return NS_OK;
}
// Set the system timezone based on the current settings.
if (aResult.isString()) {
return TimeZoneSettingObserver::SetTimeZone(aResult, cx);
}
return NS_OK;
}
NS_IMETHOD HandleError(const nsAString &aName) {
ERR("TimeZoneSettingCb::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get());
return NS_OK;
}
protected:
~TimeZoneSettingCb() {}
};
NS_IMPL_ISUPPORTS(TimeZoneSettingCb, nsISettingsServiceCallback)
TimeZoneSettingObserver::TimeZoneSettingObserver()
{
// Setup an observer to watch changes to the setting.
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (!observerService) {
ERR("GetObserverService failed");
return;
}
nsresult rv;
rv = observerService->AddObserver(this, MOZSETTINGS_CHANGED, false);
if (NS_FAILED(rv)) {
ERR("AddObserver failed");
return;
}
// Read the 'time.timezone' setting in order to start with a known
// value at boot time. The handle() will be called after reading.
nsCOMPtr<nsISettingsServiceLock> lock;
nsCOMPtr<nsISettingsService> settingsService =
do_GetService("@mozilla.org/settingsService;1");
if (!settingsService) {
ERR("Failed to get settingsLock service!");
return;
}
settingsService->CreateLock(nullptr, getter_AddRefs(lock));
nsCOMPtr<nsISettingsServiceCallback> callback = new TimeZoneSettingCb();
lock->Get(TIME_TIMEZONE, callback);
}
nsresult TimeZoneSettingObserver::SetTimeZone(const JS::Value &aValue, JSContext *aContext)
{
// Convert the JS value to a nsCString type.
// The value should be a JS string like "America/Chicago" or "UTC-05:00".
nsAutoJSString valueStr;
if (!valueStr.init(aContext, aValue.toString())) {
ERR("Failed to convert JS value to nsCString");
return NS_ERROR_FAILURE;
}
NS_ConvertUTF16toUTF8 newTimezone(valueStr);
// Hal expects opposite sign from general notations,
// so we need to flip it.
if (newTimezone.Find(NS_LITERAL_CSTRING("UTC+")) == 0) {
if (!newTimezone.SetCharAt('-', 3)) {
return NS_ERROR_FAILURE;
}
} else if (newTimezone.Find(NS_LITERAL_CSTRING("UTC-")) == 0) {
if (!newTimezone.SetCharAt('+', 3)) {
return NS_ERROR_FAILURE;
}
}
// Set the timezone only when the system timezone is not identical.
nsCString curTimezone = hal::GetTimezone();
if (!curTimezone.Equals(newTimezone)) {
hal::SetTimezone(newTimezone);
}
return NS_OK;
}
TimeZoneSettingObserver::~TimeZoneSettingObserver()
{
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
observerService->RemoveObserver(this, MOZSETTINGS_CHANGED);
}
}
NS_IMPL_ISUPPORTS(TimeZoneSettingObserver, nsIObserver)
NS_IMETHODIMP
TimeZoneSettingObserver::Observe(nsISupports *aSubject,
const char *aTopic,
const char16_t *aData)
{
if (strcmp(aTopic, MOZSETTINGS_CHANGED) != 0) {
return NS_OK;
}
// Note that this function gets called for any and all settings changes,
// so we need to carefully check if we have the one we're interested in.
//
// The string that we're interested in will be a JSON string that looks like:
// {"key":"time.timezone","value":"America/Chicago"} or
// {"key":"time.timezone","value":"UTC-05:00"}
AutoSafeJSContext cx;
RootedDictionary<SettingChangeNotification> setting(cx);
if (!WrappedJSToDictionary(cx, aSubject, setting)) {
return NS_OK;
}
if (!setting.mKey.EqualsASCII(TIME_TIMEZONE)) {
return NS_OK;
}
if (!setting.mValue.isString()) {
return NS_OK;
}
// Set the system timezone.
return SetTimeZone(setting.mValue, cx);
}
} // namespace
static mozilla::StaticRefPtr<TimeZoneSettingObserver> sTimeZoneSettingObserver;
namespace mozilla {
namespace system {
void
InitializeTimeZoneSettingObserver()
{
sTimeZoneSettingObserver = new TimeZoneSettingObserver();
ClearOnShutdown(&sTimeZoneSettingObserver);
}
} // namespace system
} // namespace mozilla

Просмотреть файл

@ -1,20 +0,0 @@
/* 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_timesetting_h__
#define mozilla_system_timesetting_h__
namespace mozilla {
namespace system {
// Initialize TimeZoneSettingObserver which observes the time zone change
// event from settings service. When receiving the event, it modifies the
// system time zone.
void InitializeTimeZoneSettingObserver();
} // namespace system
} // namespace mozilla
#endif // mozilla_system_timesetting_h__

Просмотреть файл

@ -1,596 +0,0 @@
/* 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/. */
#include "Volume.h"
#include "VolumeCommand.h"
#include "VolumeManager.h"
#include "VolumeManagerLog.h"
#include "nsIVolume.h"
#include "nsXULAppAPI.h"
#include <vold/ResponseCode.h>
namespace mozilla {
namespace system {
#if DEBUG_VOLUME_OBSERVER
void
VolumeObserverList::Broadcast(Volume* const& aVolume)
{
uint32_t size = mObservers.Length();
for (uint32_t i = 0; i < size; ++i) {
LOG("VolumeObserverList::Broadcast to [%u] %p volume '%s'",
i, mObservers[i], aVolume->NameStr());
mObservers[i]->Notify(aVolume);
}
}
#endif
VolumeObserverList Volume::sEventObserverList;
// We have a feature where volumes can be locked when mounted. This
// is used to prevent a volume from being shared with the PC while
// it is actively being used (say for storing an update image)
//
// We use WakeLocks (a poor choice of name, but it does what we want)
// from the PowerManagerService to determine when we're locked.
// In particular we'll create a wakelock called volume-NAME-GENERATION
// (where NAME is the volume name, and GENERATION is its generation
// number), and if this wakelock is locked, then we'll prevent a volume
// from being shared.
//
// Implementation Details:
//
// Since the AutoMounter can only control when something gets mounted
// and not when it gets unmounted (for example: a user pulls the SDCard)
// and because Volume and nsVolume data structures are maintained on
// separate threads, we have the potential for some race conditions.
// We eliminate the race conditions by introducing the concept of a
// generation number. Every time a volume transitions to the Mounted
// state, it gets assigned a new generation number. Whenever the state
// of a Volume changes, we send the updated state and current generation
// number to the main thread where it gets updated in the nsVolume.
//
// Since WakeLocks can only be queried from the main-thread, the
// nsVolumeService looks for WakeLock status changes, and forwards
// the results to the IOThread.
//
// If the Volume (IOThread) receives a volume update where the generation
// number mismatches, then the update is simply ignored.
//
// When a Volume (IOThread) initially becomes mounted, we assume it to
// be locked until we get our first update from nsVolume (MainThread).
static int32_t sMountGeneration = 0;
static uint32_t sNextId = 1;
// We don't get media inserted/removed events at startup. So we
// assume it's present, and we'll be told that it's missing.
Volume::Volume(const nsCSubstring& aName)
: mMediaPresent(true),
mState(nsIVolume::STATE_INIT),
mName(aName),
mMountGeneration(-1),
mMountLocked(true), // Needs to agree with nsVolume::nsVolume
mSharingEnabled(false),
mFormatRequested(false),
mMountRequested(false),
mUnmountRequested(false),
mCanBeShared(true),
mIsSharing(false),
mIsFormatting(false),
mIsUnmounting(false),
mIsRemovable(false),
mIsHotSwappable(false),
mId(sNextId++)
{
DBG("Volume %s: created", NameStr());
}
void
Volume::Dump(const char* aLabel) const
{
LOG("%s: Volume: %s (%d) is %s and %s @ %s gen %d locked %d",
aLabel,
NameStr(),
Id(),
StateStr(),
MediaPresent() ? "inserted" : "missing",
MountPoint().get(),
MountGeneration(),
(int)IsMountLocked());
LOG("%s: Sharing %s Mounting %s Formating %s Unmounting %s",
aLabel,
CanBeShared() ? (IsSharingEnabled() ? (IsSharing() ? "en-y" : "en-n")
: "dis")
: "x",
IsMountRequested() ? "req" : "n",
IsFormatRequested() ? (IsFormatting() ? "req-y" : "req-n")
: (IsFormatting() ? "y" : "n"),
IsUnmountRequested() ? (IsUnmounting() ? "req-y" : "req-n")
: (IsUnmounting() ? "y" : "n"));
}
void
Volume::ResolveAndSetMountPoint(const nsCSubstring& aMountPoint)
{
nsCString mountPoint(aMountPoint);
char realPathBuf[PATH_MAX];
// Call realpath so that we wind up with a path which is compatible with
// functions like nsVolumeService::GetVolumeByPath.
if (realpath(mountPoint.get(), realPathBuf) < 0) {
// The path we were handed doesn't exist. Warn about it, but use it
// anyways assuming that the user knows what they're doing.
ERR("ResolveAndSetMountPoint: realpath on '%s' failed: %d",
mountPoint.get(), errno);
mMountPoint = mountPoint;
} else {
mMountPoint = realPathBuf;
}
DBG("Volume %s: Setting mountpoint to '%s'", NameStr(), mMountPoint.get());
}
void Volume::SetFakeVolume(const nsACString& aMountPoint)
{
this->mMountLocked = false;
this->mCanBeShared = false;
ResolveAndSetMountPoint(aMountPoint);
SetState(nsIVolume::STATE_MOUNTED);
}
void
Volume::SetIsSharing(bool aIsSharing)
{
if (aIsSharing == mIsSharing) {
return;
}
mIsSharing = aIsSharing;
LOG("Volume %s: IsSharing set to %d state %s",
NameStr(), (int)mIsSharing, StateStr(mState));
sEventObserverList.Broadcast(this);
}
void
Volume::SetIsFormatting(bool aIsFormatting)
{
if (aIsFormatting == mIsFormatting) {
return;
}
mIsFormatting = aIsFormatting;
LOG("Volume %s: IsFormatting set to %d state %s",
NameStr(), (int)mIsFormatting, StateStr(mState));
if (mIsFormatting) {
sEventObserverList.Broadcast(this);
}
}
void
Volume::SetIsUnmounting(bool aIsUnmounting)
{
if (aIsUnmounting == mIsUnmounting) {
return;
}
mIsUnmounting = aIsUnmounting;
LOG("Volume %s: IsUnmounting set to %d state %s",
NameStr(), (int)mIsUnmounting, StateStr(mState));
sEventObserverList.Broadcast(this);
}
void
Volume::SetIsRemovable(bool aIsRemovable)
{
if (aIsRemovable == mIsRemovable) {
return;
}
mIsRemovable = aIsRemovable;
if (!mIsRemovable) {
mIsHotSwappable = false;
}
LOG("Volume %s: IsRemovable set to %d state %s",
NameStr(), (int)mIsRemovable, StateStr(mState));
sEventObserverList.Broadcast(this);
}
void
Volume::SetIsHotSwappable(bool aIsHotSwappable)
{
if (aIsHotSwappable == mIsHotSwappable) {
return;
}
mIsHotSwappable = aIsHotSwappable;
if (mIsHotSwappable) {
mIsRemovable = true;
}
LOG("Volume %s: IsHotSwappable set to %d state %s",
NameStr(), (int)mIsHotSwappable, StateStr(mState));
sEventObserverList.Broadcast(this);
}
bool
Volume::BoolConfigValue(const nsCString& aConfigValue, bool& aBoolValue)
{
if (aConfigValue.EqualsLiteral("1") ||
aConfigValue.LowerCaseEqualsLiteral("true")) {
aBoolValue = true;
return true;
}
if (aConfigValue.EqualsLiteral("0") ||
aConfigValue.LowerCaseEqualsLiteral("false")) {
aBoolValue = false;
return true;
}
return false;
}
void
Volume::SetConfig(const nsCString& aConfigName, const nsCString& aConfigValue)
{
if (aConfigName.LowerCaseEqualsLiteral("removable")) {
bool value = false;
if (BoolConfigValue(aConfigValue, value)) {
SetIsRemovable(value);
} else {
ERR("Volume %s: invalid value '%s' for configuration '%s'",
NameStr(), aConfigValue.get(), aConfigName.get());
}
return;
}
if (aConfigName.LowerCaseEqualsLiteral("hotswappable")) {
bool value = false;
if (BoolConfigValue(aConfigValue, value)) {
SetIsHotSwappable(value);
} else {
ERR("Volume %s: invalid value '%s' for configuration '%s'",
NameStr(), aConfigValue.get(), aConfigName.get());
}
return;
}
ERR("Volume %s: invalid config '%s'", NameStr(), aConfigName.get());
}
void
Volume::SetMediaPresent(bool aMediaPresent)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
// mMediaPresent is slightly redunant to the state, however
// when media is removed (while Idle), we get the following:
// 631 Volume sdcard /mnt/sdcard disk removed (179:0)
// 605 Volume sdcard /mnt/sdcard state changed from 1 (Idle-Unmounted) to 0 (No-Media)
//
// And on media insertion, we get:
// 630 Volume sdcard /mnt/sdcard disk inserted (179:0)
// 605 Volume sdcard /mnt/sdcard state changed from 0 (No-Media) to 2 (Pending)
// 605 Volume sdcard /mnt/sdcard state changed from 2 (Pending) to 1 (Idle-Unmounted)
//
// On media removal while the media is mounted:
// 632 Volume sdcard /mnt/sdcard bad removal (179:1)
// 605 Volume sdcard /mnt/sdcard state changed from 4 (Mounted) to 5 (Unmounting)
// 605 Volume sdcard /mnt/sdcard state changed from 5 (Unmounting) to 1 (Idle-Unmounted)
// 631 Volume sdcard /mnt/sdcard disk removed (179:0)
// 605 Volume sdcard /mnt/sdcard state changed from 1 (Idle-Unmounted) to 0 (No-Media)
//
// When sharing with a PC, it goes Mounted -> Idle -> Shared
// When unsharing with a PC, it goes Shared -> Idle -> Mounted
//
// The AutoMounter needs to know whether the media is present or not when
// processing the Idle state.
if (mMediaPresent == aMediaPresent) {
return;
}
LOG("Volume: %s media %s", NameStr(), aMediaPresent ? "inserted" : "removed");
mMediaPresent = aMediaPresent;
sEventObserverList.Broadcast(this);
}
void
Volume::SetSharingEnabled(bool aSharingEnabled)
{
mSharingEnabled = aSharingEnabled;
LOG("SetSharingMode for volume %s to %d canBeShared = %d",
NameStr(), (int)mSharingEnabled, (int)mCanBeShared);
sEventObserverList.Broadcast(this);
}
void
Volume::SetFormatRequested(bool aFormatRequested)
{
mFormatRequested = aFormatRequested;
LOG("SetFormatRequested for volume %s to %d CanBeFormatted = %d",
NameStr(), (int)mFormatRequested, (int)CanBeFormatted());
}
void
Volume::SetMountRequested(bool aMountRequested)
{
mMountRequested = aMountRequested;
LOG("SetMountRequested for volume %s to %d CanBeMounted = %d",
NameStr(), (int)mMountRequested, (int)CanBeMounted());
}
void
Volume::SetUnmountRequested(bool aUnmountRequested)
{
mUnmountRequested = aUnmountRequested;
LOG("SetUnmountRequested for volume %s to %d CanBeMounted = %d",
NameStr(), (int)mUnmountRequested, (int)CanBeMounted());
}
void
Volume::SetState(Volume::STATE aNewState)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
if (aNewState == mState) {
return;
}
if (aNewState == nsIVolume::STATE_MOUNTED) {
mMountGeneration = ++sMountGeneration;
LOG("Volume %s (%u): changing state from %s to %s @ '%s' (%d observers) "
"mountGeneration = %d, locked = %d",
NameStr(), mId, StateStr(mState),
StateStr(aNewState), mMountPoint.get(), sEventObserverList.Length(),
mMountGeneration, (int)mMountLocked);
} else {
LOG("Volume %s (%u): changing state from %s to %s (%d observers)",
NameStr(), mId, StateStr(mState),
StateStr(aNewState), sEventObserverList.Length());
}
switch (aNewState) {
case nsIVolume::STATE_NOMEDIA:
// Cover the startup case where we don't get insertion/removal events
mMediaPresent = false;
mIsSharing = false;
mUnmountRequested = false;
mMountRequested = false;
mIsUnmounting = false;
break;
case nsIVolume::STATE_MOUNTED:
case nsIVolume::STATE_MOUNT_FAIL:
mMountRequested = false;
mIsFormatting = false;
mIsSharing = false;
mIsUnmounting = false;
break;
case nsIVolume::STATE_FORMATTING:
mFormatRequested = false;
mIsFormatting = true;
mIsSharing = false;
mIsUnmounting = false;
break;
case nsIVolume::STATE_SHARED:
case nsIVolume::STATE_SHAREDMNT:
// Covers startup cases. Normally, mIsSharing would be set to true
// when we issue the command to initiate the sharing process, but
// it's conceivable that a volume could already be in a shared state
// when b2g starts.
mIsSharing = true;
mIsUnmounting = false;
mIsFormatting = false;
break;
case nsIVolume::STATE_UNMOUNTING:
mIsUnmounting = true;
mIsFormatting = false;
mIsSharing = false;
break;
case nsIVolume::STATE_IDLE: // Fall through
case nsIVolume::STATE_CHECKMNT: // Fall through
default:
break;
}
mState = aNewState;
sEventObserverList.Broadcast(this);
}
void
Volume::SetMountPoint(const nsCSubstring& aMountPoint)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
if (mMountPoint.Equals(aMountPoint)) {
return;
}
ResolveAndSetMountPoint(aMountPoint);
}
void
Volume::StartMount(VolumeResponseCallback* aCallback)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
StartCommand(new VolumeActionCommand(this, "mount", "", aCallback));
}
void
Volume::StartUnmount(VolumeResponseCallback* aCallback)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
StartCommand(new VolumeActionCommand(this, "unmount", "force", aCallback));
}
void
Volume::StartFormat(VolumeResponseCallback* aCallback)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
StartCommand(new VolumeActionCommand(this, "format", "", aCallback));
}
void
Volume::StartShare(VolumeResponseCallback* aCallback)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
StartCommand(new VolumeActionCommand(this, "share", "ums", aCallback));
}
void
Volume::StartUnshare(VolumeResponseCallback* aCallback)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
StartCommand(new VolumeActionCommand(this, "unshare", "ums", aCallback));
}
void
Volume::StartCommand(VolumeCommand* aCommand)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
VolumeManager::PostCommand(aCommand);
}
//static
void
Volume::RegisterVolumeObserver(Volume::EventObserver* aObserver, const char* aName)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
sEventObserverList.AddObserver(aObserver);
DBG("Added Volume Observer '%s' @%p, length = %u",
aName, aObserver, sEventObserverList.Length());
// Send an initial event to the observer (for each volume)
size_t numVolumes = VolumeManager::NumVolumes();
for (size_t volIndex = 0; volIndex < numVolumes; volIndex++) {
RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex);
aObserver->Notify(vol);
}
}
//static
void
Volume::UnregisterVolumeObserver(Volume::EventObserver* aObserver, const char* aName)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
sEventObserverList.RemoveObserver(aObserver);
DBG("Removed Volume Observer '%s' @%p, length = %u",
aName, aObserver, sEventObserverList.Length());
}
//static
void
Volume::UpdateMountLock(const nsACString& aVolumeName,
const int32_t& aMountGeneration,
const bool& aMountLocked)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
RefPtr<Volume> vol = VolumeManager::FindVolumeByName(aVolumeName);
if (!vol || (vol->mMountGeneration != aMountGeneration)) {
return;
}
if (vol->mMountLocked != aMountLocked) {
vol->mMountLocked = aMountLocked;
DBG("Volume::UpdateMountLock for '%s' to %d\n", vol->NameStr(), (int)aMountLocked);
sEventObserverList.Broadcast(vol);
}
}
void
Volume::HandleVoldResponse(int aResponseCode, nsCWhitespaceTokenizer& aTokenizer)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
// The volume name will have already been parsed, and the tokenizer will point
// to the token after the volume name
switch (aResponseCode) {
case ::ResponseCode::VolumeListResult: {
// Each line will look something like:
//
// sdcard /mnt/sdcard 1
//
nsDependentCSubstring mntPoint(aTokenizer.nextToken());
SetMountPoint(mntPoint);
nsresult errCode;
nsCString state(aTokenizer.nextToken());
if (state.EqualsLiteral("X")) {
// Special state for creating fake volumes which can't be shared.
mCanBeShared = false;
SetState(nsIVolume::STATE_MOUNTED);
} else {
SetState((STATE)state.ToInteger(&errCode));
}
break;
}
case ::ResponseCode::VolumeStateChange: {
// Format of the line looks something like:
//
// Volume sdcard /mnt/sdcard state changed from 7 (Shared-Unmounted) to 1 (Idle-Unmounted)
//
// So we parse out the state after the string " to "
while (aTokenizer.hasMoreTokens()) {
nsAutoCString token(aTokenizer.nextToken());
if (token.EqualsLiteral("to")) {
nsresult errCode;
token = aTokenizer.nextToken();
STATE newState = (STATE)(token.ToInteger(&errCode));
if (newState == nsIVolume::STATE_MOUNTED) {
// We set the state to STATE_CHECKMNT here, and the once the
// AutoMounter detects that the volume is actually accessible
// then the AutoMounter will set the volume as STATE_MOUNTED.
SetState(nsIVolume::STATE_CHECKMNT);
} else {
if (State() == nsIVolume::STATE_CHECKING && newState == nsIVolume::STATE_IDLE) {
LOG("Mount of volume '%s' failed", NameStr());
SetState(nsIVolume::STATE_MOUNT_FAIL);
} else {
SetState(newState);
}
}
break;
}
}
break;
}
case ::ResponseCode::VolumeDiskInserted:
SetMediaPresent(true);
break;
case ::ResponseCode::VolumeDiskRemoved: // fall-thru
case ::ResponseCode::VolumeBadRemoval:
SetMediaPresent(false);
break;
default:
LOG("Volume: %s unrecognized reponse code (ignored)", NameStr());
break;
}
}
} // namespace system
} // namespace mozilla

Просмотреть файл

@ -1,157 +0,0 @@
/* 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_volume_h__
#define mozilla_system_volume_h__
#include "VolumeCommand.h"
#include "nsIVolume.h"
#include "nsString.h"
#include "mozilla/Observer.h"
#include "nsISupportsImpl.h"
#include "nsWhitespaceTokenizer.h"
namespace mozilla {
namespace system {
/***************************************************************************
*
* There is an instance of the Volume class for each volume reported
* from vold.
*
* Each volume originates from the /system/etv/vold.fstab file.
*
***************************************************************************/
class Volume;
#define DEBUG_VOLUME_OBSERVER 0
#if DEBUG_VOLUME_OBSERVER
class VolumeObserverList : public mozilla::ObserverList<Volume*>
{
public:
void Broadcast(Volume* const& aVolume);
};
#else
typedef mozilla::ObserverList<Volume*> VolumeObserverList;
#endif
class Volume final
{
public:
NS_INLINE_DECL_REFCOUNTING(Volume)
Volume(const nsCSubstring& aVolumeName);
typedef long STATE; // States are now defined in nsIVolume.idl
static const char* StateStr(STATE aState) { return NS_VolumeStateStr(aState); }
const char* StateStr() const { return StateStr(mState); }
STATE State() const { return mState; }
const nsCString& Name() const { return mName; }
const char* NameStr() const { return mName.get(); }
void Dump(const char* aLabel) const;
// The mount point is the name of the directory where the volume is mounted.
// (i.e. path that leads to the files stored on the volume).
const nsCString& MountPoint() const { return mMountPoint; }
uint32_t Id() const { return mId; }
int32_t MountGeneration() const { return mMountGeneration; }
bool IsMountLocked() const { return mMountLocked; }
bool MediaPresent() const { return mMediaPresent; }
bool CanBeShared() const { return mCanBeShared; }
bool CanBeFormatted() const { return CanBeShared(); }
bool CanBeMounted() const { return CanBeShared(); }
bool IsSharingEnabled() const { return mCanBeShared && mSharingEnabled; }
bool IsFormatRequested() const { return CanBeFormatted() && mFormatRequested; }
bool IsMountRequested() const { return CanBeMounted() && mMountRequested; }
bool IsUnmountRequested() const { return CanBeMounted() && mUnmountRequested; }
bool IsSharing() const { return mIsSharing; }
bool IsFormatting() const { return mIsFormatting; }
bool IsUnmounting() const { return mIsUnmounting; }
bool IsRemovable() const { return mIsRemovable; }
bool IsHotSwappable() const { return mIsHotSwappable; }
void SetFakeVolume(const nsACString& aMountPoint);
void SetSharingEnabled(bool aSharingEnabled);
void SetFormatRequested(bool aFormatRequested);
void SetMountRequested(bool aMountRequested);
void SetUnmountRequested(bool aUnmountRequested);
typedef mozilla::Observer<Volume *> EventObserver;
// NOTE: that observers must live in the IOThread.
static void RegisterVolumeObserver(EventObserver* aObserver, const char* aName);
static void UnregisterVolumeObserver(EventObserver* aObserver, const char* aName);
protected:
~Volume() {}
private:
friend class AutoMounter; // Calls StartXxx
friend class nsVolume; // Calls UpdateMountLock
friend class VolumeManager; // Calls HandleVoldResponse
friend class VolumeListCallback; // Calls SetMountPoint, SetState
// The StartXxx functions will queue up a command to the VolumeManager.
// You can queue up as many commands as you like, and aCallback will
// be called as each one completes.
void StartMount(VolumeResponseCallback* aCallback);
void StartUnmount(VolumeResponseCallback* aCallback);
void StartFormat(VolumeResponseCallback* aCallback);
void StartShare(VolumeResponseCallback* aCallback);
void StartUnshare(VolumeResponseCallback* aCallback);
void SetIsSharing(bool aIsSharing);
void SetIsFormatting(bool aIsFormatting);
void SetIsUnmounting(bool aIsUnmounting);
void SetIsRemovable(bool aIsRemovable);
void SetIsHotSwappable(bool aIsHotSwappable);
void SetState(STATE aNewState);
void SetMediaPresent(bool aMediaPresent);
void SetMountPoint(const nsCSubstring& aMountPoint);
void StartCommand(VolumeCommand* aCommand);
void ResolveAndSetMountPoint(const nsCSubstring& aMountPoint);
bool BoolConfigValue(const nsCString& aConfigValue, bool& aBoolValue);
void SetConfig(const nsCString& aConfigName, const nsCString& aConfigValue);
void HandleVoldResponse(int aResponseCode, nsCWhitespaceTokenizer& aTokenizer);
static void UpdateMountLock(const nsACString& aVolumeName,
const int32_t& aMountGeneration,
const bool& aMountLocked);
bool mMediaPresent;
STATE mState;
const nsCString mName;
nsCString mMountPoint;
int32_t mMountGeneration;
bool mMountLocked;
bool mSharingEnabled;
bool mFormatRequested;
bool mMountRequested;
bool mUnmountRequested;
bool mCanBeShared;
bool mIsSharing;
bool mIsFormatting;
bool mIsUnmounting;
bool mIsRemovable;
bool mIsHotSwappable;
uint32_t mId; // Unique ID (used by MTP)
static VolumeObserverList sEventObserverList;
};
} // system
} // mozilla
#endif // mozilla_system_volumemanager_h__

Просмотреть файл

@ -1,85 +0,0 @@
/* 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/. */
#include "nsString.h"
#include "nsWhitespaceTokenizer.h"
#include "Volume.h"
#include "VolumeCommand.h"
#include "VolumeManager.h"
#include "VolumeManagerLog.h"
namespace mozilla {
namespace system {
/***************************************************************************
*
* The VolumeActionCommand class is used to send commands which apply
* to a particular volume.
*
* The following commands would fit into this category:
*
* volume mount <volname>
* volume unmount <volname> [force]
* volume format <volname>
* volume share <volname> <method>
* volume unshare <volname> <method>
* volume shared <volname> <method>
*
* A typical response looks like:
*
* # vdc volume unshare sdcard ums
* 605 Volume sdcard /mnt/sdcard state changed from 7 (Shared-Unmounted) to 1 (Idle-Unmounted)
* 200 volume operation succeeded
*
* Note that the 600 series of responses are considered unsolicited and
* are dealt with directly by the VolumeManager. This command will only
* see the terminating response code (200 in the example above).
*
***************************************************************************/
VolumeActionCommand::VolumeActionCommand(Volume* aVolume,
const char* aAction,
const char* aExtraArgs,
VolumeResponseCallback* aCallback)
: VolumeCommand(aCallback),
mVolume(aVolume)
{
nsAutoCString cmd;
cmd = "volume ";
cmd += aAction;
cmd += " ";
cmd += aVolume->Name().get();
// vold doesn't like trailing white space, so only add it if we really need to.
if (aExtraArgs && (*aExtraArgs != '\0')) {
cmd += " ";
cmd += aExtraArgs;
}
SetCmd(cmd);
}
/***************************************************************************
*
* The VolumeListCommand class is used to send the "volume list" command to
* vold.
*
* A typical response looks like:
*
* # vdc volume list
* 110 sdcard /mnt/sdcard 4
* 110 sdcard1 /mnt/sdcard/external_sd 4
* 200 Volumes listed.
*
***************************************************************************/
VolumeListCommand::VolumeListCommand(VolumeResponseCallback* aCallback)
: VolumeCommand(NS_LITERAL_CSTRING("volume list"), aCallback)
{
}
} // system
} // mozilla

Просмотреть файл

@ -1,204 +0,0 @@
/* 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_volumecommand_h__
#define mozilla_system_volumecommand_h__
#include "nsString.h"
#include "nsISupportsImpl.h"
#include "mozilla/RefPtr.h"
#include <algorithm>
#include <vold/ResponseCode.h>
namespace mozilla {
namespace system {
class Volume;
class VolumeCommand;
/***************************************************************************
*
* The VolumeResponseCallback class is an abstract base class. The ResponseReceived
* method will be called for each response received.
*
* Depending on the command, there may be multiple responses for the
* command. Done() will return true if this is the last response.
*
* The responses from vold are all of the form:
*
* <ResponseCode> <String>
*
* Valid Response codes can be found in the vold/ResponseCode.h header.
*
***************************************************************************/
class VolumeResponseCallback
{
protected:
virtual ~VolumeResponseCallback() {}
public:
NS_INLINE_DECL_REFCOUNTING(VolumeResponseCallback)
VolumeResponseCallback()
: mResponseCode(0), mPending(false) {}
bool Done() const
{
// Response codes from the 200, 400, and 500 series all indicated that
// the command has completed.
return (mResponseCode >= ::ResponseCode::CommandOkay)
&& (mResponseCode < ::ResponseCode::UnsolicitedInformational);
}
bool WasSuccessful() const
{
return mResponseCode == ::ResponseCode::CommandOkay;
}
bool IsPending() const { return mPending; }
int ResponseCode() const { return mResponseCode; }
const nsCString &ResponseStr() const { return mResponseStr; }
protected:
virtual void ResponseReceived(const VolumeCommand* aCommand) = 0;
private:
friend class VolumeCommand; // Calls HandleResponse and SetPending
void HandleResponse(const VolumeCommand* aCommand,
int aResponseCode,
nsACString& aResponseStr)
{
mResponseCode = aResponseCode;
#if ANDROID_VERSION >= 17
// There's a sequence number here that we don't care about
// We expect it to be 0. See VolumeCommand::SetCmd
mResponseStr = Substring(aResponseStr, 2);
#else
mResponseStr = aResponseStr;
#endif
if (mResponseCode >= ::ResponseCode::CommandOkay) {
// This is a final response.
mPending = false;
}
ResponseReceived(aCommand);
}
void SetPending(bool aPending) { mPending = aPending; }
int mResponseCode; // The response code parsed from vold
nsCString mResponseStr; // The rest of the line.
bool mPending; // Waiting for response?
};
/***************************************************************************
*
* The VolumeCommand class is an abstract base class used to encapsulate
* volume commands send to vold.
*
* See VolumeManager.h for a list of the volume commands.
*
* Commands sent to vold need an explicit null character so we add one
* to the command to ensure that it's included in the length.
*
* All of these commands are asynchronous in nature, and the
* ResponseReceived callback will be called when a response is available.
*
***************************************************************************/
class VolumeCommand
{
protected:
virtual ~VolumeCommand() {}
public:
NS_INLINE_DECL_REFCOUNTING(VolumeCommand)
VolumeCommand(VolumeResponseCallback* aCallback)
: mBytesConsumed(0),
mCallback(aCallback)
{
SetCmd(NS_LITERAL_CSTRING(""));
}
VolumeCommand(const nsACString& aCommand, VolumeResponseCallback* aCallback)
: mBytesConsumed(0),
mCallback(aCallback)
{
SetCmd(aCommand);
}
void SetCmd(const nsACString& aCommand)
{
mCmd.Truncate();
#if ANDROID_VERSION >= 17
// JB requires a sequence number at the beginning of messages.
// It doesn't matter what we use, so we use 0.
mCmd = "0 ";
#endif
mCmd.Append(aCommand);
// Add a null character. We want this to be included in the length since
// vold uses it to determine the end of the command.
mCmd.Append('\0');
}
const char* CmdStr() const { return mCmd.get(); }
const char* Data() const { return mCmd.Data() + mBytesConsumed; }
size_t BytesConsumed() const { return mBytesConsumed; }
size_t BytesRemaining() const
{
return mCmd.Length() - std::min(mCmd.Length(), mBytesConsumed);
}
void ConsumeBytes(size_t aNumBytes)
{
mBytesConsumed += std::min(BytesRemaining(), aNumBytes);
}
private:
friend class VolumeManager; // Calls SetPending & HandleResponse
void SetPending(bool aPending)
{
if (mCallback) {
mCallback->SetPending(aPending);
}
}
void HandleResponse(int aResponseCode, nsACString& aResponseStr)
{
if (mCallback) {
mCallback->HandleResponse(this, aResponseCode, aResponseStr);
}
}
nsCString mCmd; // Command being sent
size_t mBytesConsumed; // How many bytes have been sent
// Called when a response to the command is received.
RefPtr<VolumeResponseCallback> mCallback;
};
class VolumeActionCommand : public VolumeCommand
{
public:
VolumeActionCommand(Volume* aVolume, const char* aAction,
const char* aExtraArgs, VolumeResponseCallback* aCallback);
private:
RefPtr<Volume> mVolume;
};
class VolumeListCommand : public VolumeCommand
{
public:
VolumeListCommand(VolumeResponseCallback* aCallback);
};
} // system
} // mozilla
#endif // mozilla_system_volumecommand_h__

Просмотреть файл

@ -1,591 +0,0 @@
/* 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/. */
#include "VolumeManager.h"
#include "Volume.h"
#include "VolumeCommand.h"
#include "VolumeManagerLog.h"
#include "VolumeServiceTest.h"
#include "nsWhitespaceTokenizer.h"
#include "nsXULAppAPI.h"
#include "base/message_loop.h"
#include "base/task.h"
#include "mozilla/Scoped.h"
#include "mozilla/StaticPtr.h"
#include <android/log.h>
#include <cutils/sockets.h>
#include <fcntl.h>
#include <sys/socket.h>
namespace mozilla {
namespace system {
static StaticRefPtr<VolumeManager> sVolumeManager;
VolumeManager::STATE VolumeManager::mState = VolumeManager::UNINITIALIZED;
VolumeManager::StateObserverList VolumeManager::mStateObserverList;
/***************************************************************************/
VolumeManager::VolumeManager()
: LineWatcher('\0', kRcvBufSize),
mSocket(-1),
mCommandPending(false)
{
DBG("VolumeManager constructor called");
}
VolumeManager::~VolumeManager()
{
}
//static
void
VolumeManager::Dump(const char* aLabel)
{
if (!sVolumeManager) {
LOG("%s: sVolumeManager == null", aLabel);
return;
}
VolumeArray::size_type numVolumes = NumVolumes();
VolumeArray::index_type volIndex;
for (volIndex = 0; volIndex < numVolumes; volIndex++) {
RefPtr<Volume> vol = GetVolume(volIndex);
vol->Dump(aLabel);
}
}
//static
size_t
VolumeManager::NumVolumes()
{
if (!sVolumeManager) {
return 0;
}
return sVolumeManager->mVolumeArray.Length();
}
//static
already_AddRefed<Volume>
VolumeManager::GetVolume(size_t aIndex)
{
MOZ_ASSERT(aIndex < NumVolumes());
RefPtr<Volume> vol = sVolumeManager->mVolumeArray[aIndex];
return vol.forget();
}
//static
VolumeManager::STATE
VolumeManager::State()
{
return mState;
}
//static
const char *
VolumeManager::StateStr(VolumeManager::STATE aState)
{
switch (aState) {
case UNINITIALIZED: return "Uninitialized";
case STARTING: return "Starting";
case VOLUMES_READY: return "Volumes Ready";
}
return "???";
}
//static
void
VolumeManager::SetState(STATE aNewState)
{
if (mState != aNewState) {
LOG("changing state from '%s' to '%s'",
StateStr(mState), StateStr(aNewState));
mState = aNewState;
mStateObserverList.Broadcast(StateChangedEvent());
}
}
//static
void
VolumeManager::RegisterStateObserver(StateObserver* aObserver)
{
mStateObserverList.AddObserver(aObserver);
}
//static
void VolumeManager::UnregisterStateObserver(StateObserver* aObserver)
{
mStateObserverList.RemoveObserver(aObserver);
}
//static
already_AddRefed<Volume>
VolumeManager::FindVolumeByName(const nsCSubstring& aName)
{
if (!sVolumeManager) {
return nullptr;
}
VolumeArray::size_type numVolumes = NumVolumes();
VolumeArray::index_type volIndex;
for (volIndex = 0; volIndex < numVolumes; volIndex++) {
RefPtr<Volume> vol = GetVolume(volIndex);
if (vol->Name().Equals(aName)) {
return vol.forget();
}
}
return nullptr;
}
//static
already_AddRefed<Volume>
VolumeManager::FindAddVolumeByName(const nsCSubstring& aName)
{
RefPtr<Volume> vol = FindVolumeByName(aName);
if (vol) {
return vol.forget();
}
// No volume found, create and add a new one.
vol = new Volume(aName);
sVolumeManager->mVolumeArray.AppendElement(vol);
return vol.forget();
}
//static
bool
VolumeManager::RemoveVolumeByName(const nsCSubstring& aName)
{
if (!sVolumeManager) {
return false;
}
VolumeArray::size_type numVolumes = NumVolumes();
VolumeArray::index_type volIndex;
for (volIndex = 0; volIndex < numVolumes; volIndex++) {
RefPtr<Volume> vol = GetVolume(volIndex);
if (vol->Name().Equals(aName)) {
sVolumeManager->mVolumeArray.RemoveElementAt(volIndex);
return true;
}
}
// No volume found. Return false to indicate this.
return false;
}
//static
void VolumeManager::InitConfig()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
// This function uses /system/etc/volume.cfg to add additional volumes
// to the Volume Manager.
//
// This is useful on devices like the Nexus 4, which have no physical sd card
// or dedicated partition.
//
// The format of the volume.cfg file is as follows:
// create volume-name mount-point
// configure volume-name preference preference-value
// Blank lines and lines starting with the hash character "#" will be ignored.
ScopedCloseFile fp;
int n = 0;
char line[255];
const char *filename = "/system/etc/volume.cfg";
if (!(fp = fopen(filename, "r"))) {
LOG("Unable to open volume configuration file '%s' - ignoring", filename);
return;
}
while(fgets(line, sizeof(line), fp)) {
n++;
if (line[0] == '#')
continue;
nsCString commandline(line);
nsCWhitespaceTokenizer tokenizer(commandline);
if (!tokenizer.hasMoreTokens()) {
// Blank line - ignore
continue;
}
nsCString command(tokenizer.nextToken());
if (command.EqualsLiteral("create")) {
if (!tokenizer.hasMoreTokens()) {
ERR("No vol_name in %s line %d", filename, n);
continue;
}
nsCString volName(tokenizer.nextToken());
if (!tokenizer.hasMoreTokens()) {
ERR("No mount point for volume '%s'. %s line %d",
volName.get(), filename, n);
continue;
}
nsCString mountPoint(tokenizer.nextToken());
RefPtr<Volume> vol = FindAddVolumeByName(volName);
vol->SetFakeVolume(mountPoint);
continue;
}
if (command.EqualsLiteral("configure")) {
if (!tokenizer.hasMoreTokens()) {
ERR("No vol_name in %s line %d", filename, n);
continue;
}
nsCString volName(tokenizer.nextToken());
if (!tokenizer.hasMoreTokens()) {
ERR("No configuration name specified for volume '%s'. %s line %d",
volName.get(), filename, n);
continue;
}
nsCString configName(tokenizer.nextToken());
if (!tokenizer.hasMoreTokens()) {
ERR("No value for configuration name '%s'. %s line %d",
configName.get(), filename, n);
continue;
}
nsCString configValue(tokenizer.nextToken());
RefPtr<Volume> vol = FindVolumeByName(volName);
if (vol) {
vol->SetConfig(configName, configValue);
} else {
ERR("Invalid volume name '%s'.", volName.get());
}
continue;
}
if (command.EqualsLiteral("ignore")) {
// This command is useful to remove volumes which are being tracked by
// vold, but for which we have no interest.
if (!tokenizer.hasMoreTokens()) {
ERR("No vol_name in %s line %d", filename, n);
continue;
}
nsCString volName(tokenizer.nextToken());
RemoveVolumeByName(volName);
continue;
}
ERR("Unrecognized command: '%s'", command.get());
}
}
void
VolumeManager::DefaultConfig()
{
VolumeManager::VolumeArray::size_type numVolumes = VolumeManager::NumVolumes();
if (numVolumes == 0) {
return;
}
if (numVolumes == 1) {
// This is to cover early shipping phones like the Buri,
// which had no internal storage, and only external sdcard.
//
// Phones line the nexus-4 which only have an internal
// storage area will need to have a volume.cfg file with
// removable set to false.
RefPtr<Volume> vol = VolumeManager::GetVolume(0);
vol->SetIsRemovable(true);
vol->SetIsHotSwappable(true);
return;
}
VolumeManager::VolumeArray::index_type volIndex;
for (volIndex = 0; volIndex < numVolumes; volIndex++) {
RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex);
if (!vol->Name().EqualsLiteral("sdcard")) {
vol->SetIsRemovable(true);
vol->SetIsHotSwappable(true);
}
}
}
class VolumeListCallback : public VolumeResponseCallback
{
virtual void ResponseReceived(const VolumeCommand* aCommand)
{
switch (ResponseCode()) {
case ::ResponseCode::VolumeListResult: {
// Each line will look something like:
//
// sdcard /mnt/sdcard 1
//
// So for each volume that we get back, we update any volumes that
// we have of the same name, or add new ones if they don't exist.
nsCWhitespaceTokenizer tokenizer(ResponseStr());
nsDependentCSubstring volName(tokenizer.nextToken());
RefPtr<Volume> vol = VolumeManager::FindAddVolumeByName(volName);
vol->HandleVoldResponse(ResponseCode(), tokenizer);
break;
}
case ::ResponseCode::CommandOkay: {
// We've received the list of volumes. Now read the Volume.cfg
// file to perform customizations, and then tell everybody
// that we're ready for business.
VolumeManager::DefaultConfig();
VolumeManager::InitConfig();
VolumeManager::Dump("READY");
VolumeManager::SetState(VolumeManager::VOLUMES_READY);
break;
}
}
}
};
bool
VolumeManager::OpenSocket()
{
SetState(STARTING);
if ((mSocket.rwget() = socket_local_client("vold",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM)) < 0) {
ERR("Error connecting to vold: (%s) - will retry", strerror(errno));
return false;
}
// add FD_CLOEXEC flag
int flags = fcntl(mSocket.get(), F_GETFD);
if (flags == -1) {
return false;
}
flags |= FD_CLOEXEC;
if (fcntl(mSocket.get(), F_SETFD, flags) == -1) {
return false;
}
// set non-blocking
if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1) {
return false;
}
if (!MessageLoopForIO::current()->
WatchFileDescriptor(mSocket.get(),
true,
MessageLoopForIO::WATCH_READ,
&mReadWatcher,
this)) {
return false;
}
LOG("Connected to vold");
PostCommand(new VolumeListCommand(new VolumeListCallback));
return true;
}
//static
void
VolumeManager::PostCommand(VolumeCommand* aCommand)
{
if (!sVolumeManager) {
ERR("VolumeManager not initialized. Dropping command '%s'", aCommand->Data());
return;
}
aCommand->SetPending(true);
DBG("Sending command '%s'", aCommand->Data());
// vold can only process one command at a time, so add our command
// to the end of the command queue.
sVolumeManager->mCommands.push(aCommand);
if (!sVolumeManager->mCommandPending) {
// There aren't any commands currently being processed, so go
// ahead and kick this one off.
sVolumeManager->mCommandPending = true;
sVolumeManager->WriteCommandData();
}
}
/***************************************************************************
* The WriteCommandData initiates sending of a command to vold. Since
* we're running on the IOThread and not allowed to block, WriteCommandData
* will write as much data as it can, and if not all of the data can be
* written then it will setup a file descriptor watcher and
* OnFileCanWriteWithoutBlocking will call WriteCommandData to write out
* more of the command data.
*/
void
VolumeManager::WriteCommandData()
{
if (mCommands.size() == 0) {
return;
}
VolumeCommand* cmd = mCommands.front();
if (cmd->BytesRemaining() == 0) {
// All bytes have been written. We're waiting for a response.
return;
}
// There are more bytes left to write. Try to write them all.
ssize_t bytesWritten = write(mSocket.get(), cmd->Data(), cmd->BytesRemaining());
if (bytesWritten < 0) {
ERR("Failed to write %d bytes to vold socket", cmd->BytesRemaining());
Restart();
return;
}
DBG("Wrote %d bytes (of %d)", bytesWritten, cmd->BytesRemaining());
cmd->ConsumeBytes(bytesWritten);
if (cmd->BytesRemaining() == 0) {
return;
}
// We were unable to write all of the command bytes. Setup a watcher
// so we'll get called again when we can write without blocking.
if (!MessageLoopForIO::current()->
WatchFileDescriptor(mSocket.get(),
false, // one-shot
MessageLoopForIO::WATCH_WRITE,
&mWriteWatcher,
this)) {
ERR("Failed to setup write watcher for vold socket");
Restart();
}
}
void
VolumeManager::OnLineRead(int aFd, nsDependentCSubstring& aMessage)
{
MOZ_ASSERT(aFd == mSocket.get());
char* endPtr;
int responseCode = strtol(aMessage.Data(), &endPtr, 10);
if (*endPtr == ' ') {
endPtr++;
}
// Now fish out the rest of the line after the response code
nsDependentCString responseLine(endPtr, aMessage.Length() - (endPtr - aMessage.Data()));
DBG("Rcvd: %d '%s'", responseCode, responseLine.Data());
if (responseCode >= ::ResponseCode::UnsolicitedInformational) {
// These are unsolicited broadcasts. We intercept these and process
// them ourselves
HandleBroadcast(responseCode, responseLine);
} else {
// Everything else is considered to be part of the command response.
if (mCommands.size() > 0) {
VolumeCommand* cmd = mCommands.front();
cmd->HandleResponse(responseCode, responseLine);
if (responseCode >= ::ResponseCode::CommandOkay) {
// That's a terminating response. We can remove the command.
mCommands.pop();
mCommandPending = false;
// Start the next command, if there is one.
WriteCommandData();
}
} else {
ERR("Response with no command");
}
}
}
void
VolumeManager::OnFileCanWriteWithoutBlocking(int aFd)
{
MOZ_ASSERT(aFd == mSocket.get());
WriteCommandData();
}
void
VolumeManager::HandleBroadcast(int aResponseCode, nsCString& aResponseLine)
{
// Format of the line is something like:
//
// Volume sdcard /mnt/sdcard state changed from 7 (Shared-Unmounted) to 1 (Idle-Unmounted)
//
// So we parse out the volume name and the state after the string " to "
nsCWhitespaceTokenizer tokenizer(aResponseLine);
tokenizer.nextToken(); // The word "Volume"
nsDependentCSubstring volName(tokenizer.nextToken());
RefPtr<Volume> vol = FindVolumeByName(volName);
if (!vol) {
return;
}
vol->HandleVoldResponse(aResponseCode, tokenizer);
}
void
VolumeManager::Restart()
{
mReadWatcher.StopWatchingFileDescriptor();
mWriteWatcher.StopWatchingFileDescriptor();
while (!mCommands.empty()) {
mCommands.pop();
}
mCommandPending = false;
mSocket.dispose();
Start();
}
//static
void
VolumeManager::Start()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
if (!sVolumeManager) {
return;
}
SetState(STARTING);
if (!sVolumeManager->OpenSocket()) {
// Socket open failed, try again in a second.
MessageLoopForIO::current()->
PostDelayedTask(NewRunnableFunction(VolumeManager::Start),
1000);
}
}
void
VolumeManager::OnError()
{
Restart();
}
/***************************************************************************/
static void
InitVolumeManagerIOThread()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
MOZ_ASSERT(!sVolumeManager);
sVolumeManager = new VolumeManager();
VolumeManager::Start();
InitVolumeServiceTestIOThread();
}
static void
ShutdownVolumeManagerIOThread()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
sVolumeManager = nullptr;
}
/**************************************************************************
*
* Public API
*
* Since the VolumeManager runs in IO Thread context, we need to switch
* to IOThread context before we can do anything.
*
**************************************************************************/
void
InitVolumeManager()
{
XRE_GetIOMessageLoop()->PostTask(
NewRunnableFunction(InitVolumeManagerIOThread));
}
void
ShutdownVolumeManager()
{
ShutdownVolumeServiceTest();
XRE_GetIOMessageLoop()->PostTask(
NewRunnableFunction(ShutdownVolumeManagerIOThread));
}
} // system
} // mozilla

Просмотреть файл

@ -1,192 +0,0 @@
/* 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_volumemanager_h__
#define mozilla_system_volumemanager_h__
#include <vector>
#include <queue>
#include "base/message_loop.h"
#include "mozilla/FileUtils.h"
#include "mozilla/Observer.h"
#include "nsISupportsImpl.h"
#include "nsString.h"
#include "nsTArray.h"
#include "Volume.h"
#include "VolumeCommand.h"
namespace mozilla {
namespace system {
/***************************************************************************
*
* All of the public API mentioned in this file (unless otherwise
* mentioned) must run from the IOThread.
*
***************************************************************************/
/***************************************************************************
*
* The VolumeManager class is a front-end for android's vold service.
*
* Vold uses a unix socket interface and accepts null-terminated string
* commands. The following commands were determined by examining the vold
* source code:
*
* volume list
* volume mount <volname>
* volume unmount <volname> [force]
* volume debug [on|off]
* volume format <volname>
* volume share <volname> <method>
* volume unshare <volname> <method>
* volume shared <volname> <method>
*
* <volname> is the name of the volume as used in /system/etc/vold.fstab
* <method> is ums
*
* dump
*
* share status <method> (Determines if a particular sharing method is available)
* (GB only - not available in ICS)
*
* storage users (??? always crashes vold ???)
*
* asec list
* asec ...lots more...
*
* obb list
* obb ...lots more...
*
* xwarp enable
* xwarp disable
* xwarp status
*
* There is also a command line tool called vdc, which can be used to send
* the above commands to vold.
*
* Currently, only the volume list, share/unshare, and mount/unmount
* commands are being used.
*
***************************************************************************/
class VolumeManager final : public MessageLoopForIO::LineWatcher
{
virtual ~VolumeManager();
public:
NS_INLINE_DECL_REFCOUNTING(VolumeManager)
typedef nsTArray<RefPtr<Volume>> VolumeArray;
VolumeManager();
//-----------------------------------------------------------------------
//
// State related methods.
//
// The VolumeManager starts off in the STARTING state. Once a connection
// is established with vold, it asks for a list of volumes, and once the
// volume list has been received, then the VolumeManager enters the
// VOLUMES_READY state.
//
// If vold crashes, then the VolumeManager will once again enter the
// STARTING state and try to reestablish a connection with vold.
enum STATE
{
UNINITIALIZED,
STARTING,
VOLUMES_READY
};
static STATE State();
static const char* StateStr(STATE aState);
static const char* StateStr() { return StateStr(State()); }
class StateChangedEvent
{
public:
StateChangedEvent() {}
};
typedef mozilla::Observer<StateChangedEvent> StateObserver;
typedef mozilla::ObserverList<StateChangedEvent> StateObserverList;
static void RegisterStateObserver(StateObserver* aObserver);
static void UnregisterStateObserver(StateObserver* aObserver);
//-----------------------------------------------------------------------
static void Start();
static void Dump(const char* aLabel);
static VolumeArray::size_type NumVolumes();
static already_AddRefed<Volume> GetVolume(VolumeArray::index_type aIndex);
static already_AddRefed<Volume> FindVolumeByName(const nsCSubstring& aName);
static already_AddRefed<Volume> FindAddVolumeByName(const nsCSubstring& aName);
static bool RemoveVolumeByName(const nsCSubstring& aName);
static void InitConfig();
static void PostCommand(VolumeCommand* aCommand);
protected:
virtual void OnLineRead(int aFd, nsDependentCSubstring& aMessage);
virtual void OnFileCanWriteWithoutBlocking(int aFd);
virtual void OnError();
static void DefaultConfig();
private:
bool OpenSocket();
friend class VolumeListCallback; // Calls SetState
static void SetState(STATE aNewState);
void Restart();
void WriteCommandData();
void HandleBroadcast(int aResponseCode, nsCString& aResponseLine);
typedef std::queue<RefPtr<VolumeCommand> > CommandQueue;
static STATE mState;
static StateObserverList mStateObserverList;
static const int kRcvBufSize = 1024;
ScopedClose mSocket;
VolumeArray mVolumeArray;
CommandQueue mCommands;
bool mCommandPending;
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
RefPtr<VolumeResponseCallback> mBroadcastCallback;
};
/***************************************************************************
*
* The initialization/shutdown functions do not need to be called from
* the IOThread context.
*
***************************************************************************/
/**
* Initialize the Volume Manager. On initialization, the VolumeManager will
* attempt to connect with vold and collect the list of volumes that vold
* knows about.
*/
void InitVolumeManager();
/**
* Shuts down the Volume Manager.
*/
void ShutdownVolumeManager();
} // system
} // mozilla
#endif // mozilla_system_volumemanager_h__

Просмотреть файл

@ -1,27 +0,0 @@
/* 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_volumemanagerlog_h__
#define mozilla_system_volumemanagerlog_h__
#undef USE_DEBUG
#define USE_DEBUG 0
#if !defined(VOLUME_MANAGER_LOG_TAG)
#define VOLUME_MANAGER_LOG_TAG "VolumeManager"
#endif
#undef LOG
#undef ERR
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, VOLUME_MANAGER_LOG_TAG, ## args)
#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, VOLUME_MANAGER_LOG_TAG, ## args)
#undef DBG
#if USE_DEBUG
#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, VOLUME_MANAGER_LOG_TAG, ## args)
#else
#define DBG(args...)
#endif
#endif // mozilla_system_volumemanagerlog_h__

Просмотреть файл

@ -1,82 +0,0 @@
/* 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/. */
#include "VolumeServiceIOThread.h"
#include "base/message_loop.h"
#include "nsVolumeService.h"
#include "nsXULAppAPI.h"
#include "Volume.h"
#include "VolumeManager.h"
namespace mozilla {
namespace system {
VolumeServiceIOThread::VolumeServiceIOThread(nsVolumeService* aVolumeService)
: mVolumeService(aVolumeService)
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
VolumeManager::RegisterStateObserver(this);
Volume::RegisterVolumeObserver(this, "VolumeServiceIOThread");
UpdateAllVolumes();
}
VolumeServiceIOThread::~VolumeServiceIOThread()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
Volume::UnregisterVolumeObserver(this, "VolumeServiceIOThread");
VolumeManager::UnregisterStateObserver(this);
}
void
VolumeServiceIOThread::Notify(Volume* const & aVolume)
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
if (VolumeManager::State() != VolumeManager::VOLUMES_READY) {
return;
}
mVolumeService->UpdateVolumeIOThread(aVolume);
}
void
VolumeServiceIOThread::Notify(const VolumeManager::StateChangedEvent& aEvent)
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
UpdateAllVolumes();
}
void
VolumeServiceIOThread::UpdateAllVolumes()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
if (VolumeManager::State() != VolumeManager::VOLUMES_READY) {
return;
}
VolumeManager::VolumeArray::size_type numVolumes = VolumeManager::NumVolumes();
VolumeManager::VolumeArray::index_type volIndex;
for (volIndex = 0; volIndex < numVolumes; volIndex++) {
RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex);
mVolumeService->UpdateVolumeIOThread(vol);
}
}
static StaticRefPtr<VolumeServiceIOThread> sVolumeServiceIOThread;
void
InitVolumeServiceIOThread(nsVolumeService* const & aVolumeService)
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
sVolumeServiceIOThread = new VolumeServiceIOThread(aVolumeService);
}
void
ShutdownVolumeServiceIOThread()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
sVolumeServiceIOThread = nullptr;
}
} // system
} // mozilla

Просмотреть файл

@ -1,49 +0,0 @@
/* 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_volumeserviceiothread_h__
#define mozilla_system_volumeserviceiothread_h__
#include "Volume.h"
#include "VolumeManager.h"
#include "mozilla/RefPtr.h"
namespace mozilla {
namespace system {
class nsVolumeService;
/***************************************************************************
* The nsVolumeServiceIOThread is a companion class to the nsVolumeService
* class, but whose methods are called from IOThread.
*/
class VolumeServiceIOThread : public VolumeManager::StateObserver,
public Volume::EventObserver
{
~VolumeServiceIOThread();
public:
NS_INLINE_DECL_REFCOUNTING(VolumeServiceIOThread)
VolumeServiceIOThread(nsVolumeService* aVolumeService);
private:
void UpdateAllVolumes();
virtual void Notify(const VolumeManager::StateChangedEvent& aEvent);
virtual void Notify(Volume* const & aVolume);
RefPtr<nsVolumeService> mVolumeService;
};
void InitVolumeServiceIOThread(nsVolumeService* const & aVolumeService);
void ShutdownVolumeServiceIOThread();
void FormatVolume(const nsCString& aVolume);
void MountVolume(const nsCString& aVolume);
void UnmountVolume(const nsCString& aVolume);
} // system
} // mozilla
#endif // mozilla_system_volumeserviceiothread_h__

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше