Closed
Bug 820704
Opened 12 years ago
Closed 12 years ago
Failure in "MW1: Music stays alive"; Music playback pauses when in background, unexpectedly
Categories
(Core :: Audio/Video, defect, P1)
Tracking
()
People
(Reporter: cjones, Assigned: baku)
References
Details
Attachments
(1 file, 4 obsolete files)
13.09 KB,
patch
|
baku
:
review+
|
Details | Diff | Splinter Review |
+++ This bug was initially created as a clone of Bug #820702 +++
STR
(1) Follow the steps at https://wiki.mozilla.org/B2G/Memory_acceptance_criteria#MW0:_Every_app_is_successfully_launched_into_the_foreground_.5BPASS.5D
(2) After step 18, the homescreen failed to load
Switching to a different app and back to homescreen, locking and unlocking the screen, repeatedly tapping where the homescreen should have been, failed to get it to reload.
Extremely bad bug.
Reporter | ||
Comment 1•12 years ago
|
||
Damnable fat-fingering.
STR
(1) Follow the steps at https://wiki.mozilla.org/B2G/Memory_acceptance_criteria#MW1:_Music_stays_alive_.5BUNEXPECTED-
(2) After step 4, the music stream pauses
Broken feature.
Severity: critical → normal
blocking-basecamp: --- → ?
No longer depends on: 820702
Priority: P1 → --
Summary: Failure in "MW0: Every app is successfully launched into the foreground"; Homescreen app fails to load → Failure in "MW1: Music stays alive"; Music playback pauses when in background, unexpectedly
Comment 2•12 years ago
|
||
Andrea, please investigate.
Assignee: nobody → amarchesini
blocking-basecamp: ? → +
Priority: -- → P1
Target Milestone: --- → B2G C3 (12dec-1jan)
Comment 3•12 years ago
|
||
dhylands opined that the music app was perhaps killed in the background.
Reporter | ||
Comment 4•12 years ago
|
||
No, that's not the case. Playback stops immediately when after the music app is sent to the background. See comment 0.
Assignee | ||
Comment 6•12 years ago
|
||
(In reply to Andrew Overholt [:overholt] from comment #2)
> Andrea, please investigate.
I cannot reproduce this bug. I'm using the latest code from central + gaia.
The Music playback continues perfectly after step 4. I have problems after step 11, but this is not related to the audio: the homescreen doesn't appear and I cannot continue with step 12.
Reporter | ||
Comment 7•12 years ago
|
||
STR
(1) Open music app
(2) Play song
(3) Send to background (go to homescreen)
(4) Open task switcher and kill music app
(5) Re-open music app and play song again
(6) Send to background
Playback stops.
Reporter | ||
Updated•12 years ago
|
Whiteboard: DUPEME
Reporter | ||
Comment 8•12 years ago
|
||
Comment 7 implicates me in not running a clean test in comment 0, so this isn't blocking memory tests anymore.
However, that doesn't change the nature of this bug.
No longer blocks: 815348
Assignee | ||
Comment 9•12 years ago
|
||
> (1) Open music app
> (2) Play song
> (3) Send to background (go to homescreen)
> (4) Open task switcher and kill music app
> (5) Re-open music app and play song again
> (6) Send to background
I see the bug. Thanks. /me working on it.
Assignee | ||
Comment 10•12 years ago
|
||
This fixes the problem but I need a feedback.
With this patch we store the appIds in the audio channel service. Then when the child process quits, we call RemoveAppIds().
This patch doesn't involve FMRadio because there is not an easy way to get the appid and we don't support properly multiple apps using FMRadio at the same time.
Attachment #692291 -
Flags: review?(jonas)
Attachment #692291 -
Flags: feedback?(mchen)
Comment 11•12 years ago
|
||
Is this a dup of bug 815355?
Reporter | ||
Comment 12•12 years ago
|
||
Nope, different bugs that occur on the same testcase.
Comment on attachment 692291 [details] [diff] [review]
patch
Review of attachment 692291 [details] [diff] [review]:
-----------------------------------------------------------------
::: dom/audiochannel/AudioChannelService.cpp
@@ +68,5 @@
>
> AudioChannelService::AudioChannelService()
> : mCurrentHigherChannel(AUDIO_CHANNEL_NORMAL)
> {
> + mChannelCounters = new nsTArray<uint32_t>[AUDIO_CHANNEL_PUBLICNOTIFICATION+1];
Why not make mChannelCounters of type:
nsTArray<uint32_t>[AUDIO_CHANNEL_PUBLICNOTIFICATION+1];
@@ +76,5 @@
> }
>
> AudioChannelService::~AudioChannelService()
> {
> delete [] mChannelCounters;
...and remove this.
@@ +117,2 @@
> {
> + mChannelCounters[aType].RemoveElement(aAppId);
Add a note that there might be multiple elements with the same appid in the array and this will, and should, only remove the first one.
@@ +223,5 @@
> }
>
> +PLDHashOperator
> +AudioChannelService::NotifyEnumerator(AudioChannelAgent* aAgent,
> + AudioChannelAgentData aData, void* aUnused)
Put a "// static" comment above this to show that it's static. We do this somewhat consistently in gecko code.
@@ +297,5 @@
> void
> AudioChannelService::SetPhoneInCall(bool aActive)
> {
> //while ring tone and in-call mode, mute media element
> + if (aActive && mChannelCounters[AUDIO_CHANNEL_TELEPHONY].IsEmpty()) {
Leave a comment, (and file a followup if you are so inclined) on that this should ideally pass in a appid too.
@@ +313,5 @@
> + for (int32_t type = AUDIO_CHANNEL_NORMAL;
> + type <= AUDIO_CHANNEL_PUBLICNOTIFICATION;
> + ++type) {
> + while (mChannelCounters[type].Contains(aAppId)) {
> + mChannelCounters[type].RemoveElement(aAppId);
Not a huge deal, but a faster/cleaner solution would be to add
nsTArray::RemoveAllElements(value)
Actually, a pair of them, one with a comparator and one using the default comparator. See how RemoveElement(...) is implemented.
But not a huge deal.
::: dom/ipc/TabParent.cpp
@@ +159,5 @@
> +
> + AudioChannelService *service = AudioChannelService::GetAudioChannelService();
> + if (service) {
> + service->RemoveAppId(OwnAppId());
> + }
Justin should review this change
Attachment #692291 -
Flags: review?(jonas) → review+
Comment on attachment 692291 [details] [diff] [review]
patch
Justin: Can you review the TabParent.cpp change? Is that the only place where we need to do cleanup for a child process that went away?
Attachment #692291 -
Flags: review?(justin.lebar+bug)
Comment 15•12 years ago
|
||
> Is that the only place where we need to do cleanup for a child process that went away?
Yes, I'm pretty sure that's fine. I'd prefer if it was loosely-coupled, however -- that is, if we fired an observer instead of sticking the audio manager code into TabParent.
But I'm confused about what this patch is doing. It seems like we're using appIds as a way to identify PBrowsers? But that's not really correct. In particular, multiple processes could all have appId 0.
What are we using the appId for?
> void
> AudioChannelService::SetPhoneInCall(bool aActive)
> {
> //while ring tone and in-call mode, mute media element
>- if (aActive) {
>- mChannelCounters[AUDIO_CHANNEL_TELEPHONY] = 1;
>- } else {
>- mChannelCounters[AUDIO_CHANNEL_TELEPHONY] = 0;
>+ if (aActive && mChannelCounters[AUDIO_CHANNEL_TELEPHONY].IsEmpty()) {
>+ mChannelCounters[AUDIO_CHANNEL_TELEPHONY].AppendElement(0);
>+ } else if(!aActive && !mChannelCounters[AUDIO_CHANNEL_TELEPHONY].IsEmpty()) {
>+ mChannelCounters[AUDIO_CHANNEL_TELEPHONY].RemoveElement(0);
Is this safe given the implementation of RemoveAppId()? That is, what happens
if I call RemoveAppId(0) while we're in an active call?
Updated•12 years ago
|
Whiteboard: DUPEME
Assignee | ||
Comment 16•12 years ago
|
||
> But I'm confused about what this patch is doing. It seems like we're using
> appIds as a way to identify PBrowsers? But that's not really correct. In
> particular, multiple processes could all have appId 0.
Basically the idea is that when an app quits, we have to remove any count/reference to its audio channel components.
> Is this safe given the implementation of RemoveAppId()? That is, what
> happens
> if I call RemoveAppId(0) while we're in an active call?
0 is not allowed and the telephony channel is used by appId 0.
Comment 17•12 years ago
|
||
> 0 is not allowed and the telephony channel is used by appId 0.
I don't see anything preventing the TabParent code from calling this function with appId == 0, though. OwnAppId() may be 0.
> Basically the idea is that when an app quits, we have to remove any count/reference to
> its audio channel components.
A TabParent being destroyed is not really the same thing as an app quitting. For example, the browser app runs inside the main process and doesn't have a TabParent. Are we handling this properly?
+++ b/dom/ipc/PContent.ipdl
> + async AudioChannelRegisterType(AudioChannelType aType, uint32_t aAppId);
> + async AudioChannelUnregisterType(AudioChannelType aType, uint32_t aAppId);
Do we want to be trusting the child to supply correct appIds here? Perhaps a better way to do this would be to send PBrowser's through the IPDL interface.
(In reply to Justin Lebar [:jlebar] from comment #17)
> > 0 is not allowed and the telephony channel is used by appId 0.
>
> I don't see anything preventing the TabParent code from calling this
> function with appId == 0, though. OwnAppId() may be 0.
When can OwnAppId()==0 in B2G? Should we simply not call RemoveAppId if AppId returns 0?
> > Basically the idea is that when an app quits, we have to remove any count/reference to
> > its audio channel components.
>
> A TabParent being destroyed is not really the same thing as an app quitting.
> For example, the browser app runs inside the main process and doesn't have a
> TabParent. Are we handling this properly?
I think we are. The normal shutdown path is that all media elements unregister with the AudioChannelService in their process when they are stopped.
The problem this bug is covering is when we don't shut down the normal way, such as when a child process is killed.
> +++ b/dom/ipc/PContent.ipdl
> > + async AudioChannelRegisterType(AudioChannelType aType, uint32_t aAppId);
> > + async AudioChannelUnregisterType(AudioChannelType aType, uint32_t aAppId);
>
> Do we want to be trusting the child to supply correct appIds here? Perhaps
> a better way to do this would be to send PBrowser's through the IPDL
> interface.
I don't care strongly. We haven't secured the audio channels code against child processes getting hacked so far. I suggest we do that as a followup since the failure case isn't bad enough to be blocking IMO.
Comment 19•12 years ago
|
||
> When can OwnAppId()==0 in B2G?
A browser tab process has OwnAppId() == 0. See the comments in TabContext.h for an explanation of what these attributes mean.
I don't think we ever have OwnOrContainingAppId() == 0 in B2G. I think that might be correct for your purposes here, but it would break with nested content processes, because then you could have two processes with the same OwnOrContainingAppId()'s.
> The problem this bug is covering is when we don't shut down the normal way, such as when a child
> process is killed.
Then should we run this code only when the child process shuts down abnormally?
I still feel like using AppIds to identify TabParent objects is a hack. I'm not in a position to judge whether we need to accept technical debt to Get This Fixed Now, but in my experience, these follow-ups are rarely done, and the debt is rarely repaid.
Comment 20•12 years ago
|
||
If you do switch to OwnOrContianingAppId(), please add an assertion in the code that the ID you get is not 0, if the correctness of the code relies on that.
Ah, yes, I see what you mean that using appids rather than TabParents is the wrong thing.
In particular, if we have two child processes that both are running pages from the same appid then things break down.
I can think of three ways forward:
1. Use the current solution for now.
2. Rather than sending AudioChannelRegisterType/AudioChannelUnregisterType
messages to the parent process, create a new protocol object and send
constructors and destructors. When the child process goes away the protocol
object will automatically be destroyed and so will take care of unregistering
automatically.
3. Keep AudioChannelRegisterType/AudioChannelUnregisterType, but send a
TabParent as the second argument rather than an appid. Then track things
by TabParent in the AudioChannelService. When the TabParent goes away we
tell the AudioChannelService and it'll unregister things keyed on TabParent
rather than appid.
Comment 22•12 years ago
|
||
> In particular, if we have two child processes that both are running pages from the same appid then
> things break down.
Yes, exactly. And at the very least, we spawn multiple browser tab processes, all with OwnAppId == 0 (and with the same OwnOrContainingAppId(), corresponding to that of the browser app).
Blocks: 823438
Assignee | ||
Comment 23•12 years ago
|
||
Justin, can you take a look of this usage of mChildID ?
Attachment #692291 -
Attachment is obsolete: true
Attachment #692291 -
Flags: review?(justin.lebar+bug)
Attachment #692291 -
Flags: feedback?(mchen)
Attachment #694497 -
Flags: review?(justin.lebar+bug)
Assignee | ||
Comment 24•12 years ago
|
||
sorry, wrong page. Can you review this?
Attachment #694497 -
Attachment is obsolete: true
Attachment #694497 -
Flags: review?(justin.lebar+bug)
Attachment #694499 -
Flags: review?(justin.lebar+bug)
Comment 25•12 years ago
|
||
Comment on attachment 694499 [details] [diff] [review]
patch a
> void
>-AudioChannelService::UnregisterType(AudioChannelType aType)
>+AudioChannelService::UnregisterType(AudioChannelType aType, uint64_t aChildID)
> {
>- mChannelCounters[aType]--;
>- MOZ_ASSERT(mChannelCounters[aType] >= 0);
>+ // The array may contain multiple occurrence of this appId but
>+ // this should remove only the first one.
>+ mChannelCounters[aType].RemoveElement(aChildID);
Update this comment?
>diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp
>--- a/dom/ipc/TabParent.cpp
>+++ b/dom/ipc/TabParent.cpp
>@@ -150,16 +151,22 @@ TabParent::ActorDestroy(ActorDestroyReas
> if (why == AbnormalShutdown) {
> nsCOMPtr<nsIObserverService> os = services::GetObserverService();
> if (os) {
> os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, frameLoader),
> "oop-frameloader-crashed", nullptr);
> }
> }
> }
>+
>+ AudioChannelService *service = AudioChannelService::GetAudioChannelService();
>+ if (service) {
>+ ContentParent* cp = static_cast<ContentParent*>(Manager());
>+ service->RemoveChildID(cp->ChildID());
>+ }
This assumes that the ContentChild has died any time we destroy a TabParent,
but that's not right. For example, if we have two windows in a process (e.g. a
main window and a popup window generated via window.open), each window gets its
own TabParent, and we can close one TabParent without killing the whole
process.
I think you want ContentParent::ActorDestroy.
But then notice that ContentParent::ActorDestroy already notifies the observer service:
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nullptr);
and one of the properties is the childID:
props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), mChildID);
So I think you can just listen to ipc:content-shutdown.
The changes in ContentParent.{cpp,h} look fine to me, although I'm not positive cjones is OK with me reviewing this stuff. I have a message into him. But I guess if you make this change you won't need to modify anything other than the AudioChannel call in ContentParent.
Attachment #694499 -
Flags: review?(justin.lebar+bug)
Assignee | ||
Comment 26•12 years ago
|
||
Wow, I love this observer approach. Code is much more readable.
Justin, give me a feedback. Then I'll ask cjones for reviewing the ContentParent part, and then Jonas will review the rest.
Attachment #694499 -
Attachment is obsolete: true
Attachment #694756 -
Flags: review?(justin.lebar+bug)
Comment on attachment 694756 [details] [diff] [review]
patch b
Maybe chris can review the use of the new ContentParent::ChildId function here.
Chris: The goal of this patch is to handle unregistering media elements (and other sound sources) in child processes that crash or are otherwise killed.
Attachment #694756 -
Flags: review?(jones.chris.g)
Comment 28•12 years ago
|
||
I'd really prefer to have a look at this, if I can; I've found non-trivial bugs in the past few similar patches I've reviewed.
Are you OK waiting until I have time, Jonas?
Comment on attachment 694756 [details] [diff] [review]
patch b
Sure, that's ok. We are getting a non-trivial amount of dupes/dependencies though, so please put this high on your list.
Attachment #694756 -
Flags: review?(jones.chris.g)
Comment 30•12 years ago
|
||
Comment on attachment 694756 [details] [diff] [review]
patch b
When have I ever left you hanging for a review, Jonas? :)
>@@ -293,8 +291,41 @@ AudioChannelService::ChannelName(AudioCh
>+NS_IMETHODIMP
>+AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* data)
>+{
>+ MOZ_ASSERT(!strcmp(aTopic, "ipc:content-shutdown"));
>+
>+ nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
>+ if (!props) {
>+ NS_WARNING("ipc:content-shutdown message without property bag as subject");
>+ return NS_OK;
>+ }
>+
>+ uint64_t childID = 0;
>+ nsresult rv = props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"),
>+ &childID);
>+ if (NS_SUCCEEDED(rv)) {
>+ for (int32_t type = AUDIO_CHANNEL_NORMAL;
>+ type <= AUDIO_CHANNEL_PUBLICNOTIFICATION;
>+ ++type) {
>+ while (mChannelCounters[type].Contains(childID)) {
>+ mChannelCounters[type].RemoveElement(childID);
>+ }
Not to prematurely optimize, but this is a pretty inefficient way of doing
this. Perhaps you could could at least do an IndexOf and then remove that
index.
>+ // We don't have to remove the agents from the mAgents hashtable because if
>+ // that table contains only agents running on the same process.
Fix this comment (the "if"), please.
r=me; thanks for waiting. :)
Attachment #694756 -
Flags: review?(justin.lebar+bug) → review+
Assignee | ||
Comment 31•12 years ago
|
||
Thanks for this review. After green on try, I mark this patch for checking in.
Attachment #694756 -
Attachment is obsolete: true
Attachment #696122 -
Flags: review+
Assignee | ||
Updated•12 years ago
|
Keywords: checkin-needed
Assignee | ||
Comment 32•12 years ago
|
||
https://tbpl.mozilla.org/?tree=Try&rev=68ec7c07711d green on try
Comment 34•12 years ago
|
||
Keywords: checkin-needed
Comment 35•12 years ago
|
||
Status: NEW → RESOLVED
Closed: 12 years ago
Resolution: --- → FIXED
Comment 36•12 years ago
|
||
You need to log in
before you can comment on or make changes to this bug.
Description
•