Closed
Bug 785124
Opened 12 years ago
Closed 12 years ago
B2G Updates: Download Gecko updates with better fallbacks
Categories
(Toolkit :: Application Update, defect, P1)
Tracking
()
People
(Reporter: marshall, Assigned: dhylands)
References
()
Details
Attachments
(8 files, 7 obsolete files)
19.30 KB,
patch
|
marshall
:
review+
|
Details | Diff | Splinter Review |
58.55 KB,
patch
|
dougt
:
review+
|
Details | Diff | Splinter Review |
52.76 KB,
patch
|
dougt
:
review+
|
Details | Diff | Splinter Review |
5.10 KB,
patch
|
robert.strong.bugs
:
review+
|
Details | Diff | Splinter Review |
7.96 KB,
patch
|
dougt
:
review+
|
Details | Diff | Splinter Review |
3.60 KB,
patch
|
marshall
:
review+
|
Details | Diff | Splinter Review |
1.64 KB,
patch
|
jduell.mcbugs
:
review+
|
Details | Diff | Splinter Review |
3.74 KB,
patch
|
jst
:
review+
|
Details | Diff | Splinter Review |
Downloading updates for B2G will need to follow this basic flow:
- When an available update is found, make sure there is enough space on /sdcard (external storage)
- When there isn't enough space, or the sdcard isn't available, check space on /data/local
- If neither has enough space, show the user a prompt asking them to clear up space, and try again in 30 minutes
- Once a location with enough space has been found, start the download
- If the disk runs out of space during the download:
-- If we were downloading to /sdcard, we can check space on /data/local, and if there is enough space, move the partial file there, and resume the download.
-- Otherwise, prompt the user to clear up space, and try again in 30 minutes
Reporter | ||
Updated•12 years ago
|
blocking-basecamp: --- → ?
Reporter | ||
Comment 1•12 years ago
|
||
Looks like this nom was missed. We will need this logic in v1..
+cjones overholt
Priority: -- → P1
Comment 2•12 years ago
|
||
Blocking based on comment #1 and an IRC conversation with Marshall regarding how implementing this follows the UX spec, etc.
blocking-basecamp: ? → +
Reporter | ||
Comment 3•12 years ago
|
||
Posting this WIP for cjones
Will see how much further I can push this along.
Assignee: marshall → jones.chris.g
Updated•12 years ago
|
Assignee: jones.chris.g → fabrice
Assignee | ||
Comment 7•12 years ago
|
||
Fabrice - I'll give it a go
Comment 8•12 years ago
|
||
I hit some updater issues today, and marshall_law suggested I mention them here, since hopefully this bug should resolve them.
I was being offered the second (~10 MB) OTA update that was posted today. When I accepted the prompt, my phone would download the full update, but then not bother to apply it. (It stopped before the standard "[ ======= ]" progress bar that normally shows up in logcat output) I never got an "Install update" prompt.
It turned out to be that the updater relies on sdcard access, and my phone was connected to my laptop w/ mass storage enabled -- so, the sdcard was unavailable to the updater.
I was able to successfully get the update by disabling mass storage mode, rebooting, and trying again.
Comment 9•12 years ago
|
||
That should be handled by B2G directly instead of application update by returning an appropriate value for "UpdRootD".
Reporter | ||
Comment 10•12 years ago
|
||
(In reply to Robert Strong [:rstrong] (do not email) from comment #9)
> That should be handled by B2G directly instead of application update by
> returning an appropriate value for "UpdRootD".
Agreed. Dave has plans to lock down the sdcard for the updater while an update is being downloaded / applied, and I wanted to make sure we logged that use case here, since the patch is still a WIP.
Assignee | ||
Updated•12 years ago
|
Assignee | ||
Comment 11•12 years ago
|
||
This adds the VolumeMountLock class, and associated support, which while the instance of the class exists, will prevent a mounted volume from being shared with the PC.
Attachment #685950 -
Flags: feedback?(doug.turner)
Assignee | ||
Comment 12•12 years ago
|
||
And oh yeah - there's a big comment block in Volume.cpp that explains the overall design of what this change is doing.
Comment 13•12 years ago
|
||
ETA please? last activity was about a week ago!
Assignee | ||
Comment 14•12 years ago
|
||
Not sure on the ETA. The part that I'm most familiar with is done and awaiting feedback from Doug Turner.
I'm now working on the JS part and I've got the JS attached to the patch working (it needed some changes).
Comment 15•12 years ago
|
||
Comment on attachment 685950 [details] [diff] [review]
WIP - Add ability to lock a mount
Review of attachment 685950 [details] [diff] [review]:
-----------------------------------------------------------------
::: dom/ipc/ContentChild.cpp
@@ +1094,5 @@
> + // Remove warnings about unused arguments
> + (void)aFsName;
> + (void)aName;
> + (void)aState;
> + (void)aMountGeneration;
does this work everywhere? not sure about some of the crap compilers we use.
::: dom/system/gonk/Volume.cpp
@@ +98,3 @@
>
> void
> Volume::SetState(Volume::STATE aNewState)
This only can happen on one thread, right? It might be good to add an assertion.
::: dom/system/gonk/Volume.h
@@ +42,5 @@
> // (i.e. path that leads to the files stored on the volume).
> const nsCString &MountPoint() const { return mMountPoint; }
>
> + int32_t MountGeneration() const { return mMountGeneration; }
> + bool IsMountLocked() const { return mMountLocked; }
just once space between the return type and the method name.
@@ +74,5 @@
> void StartCommand(VolumeCommand *aCommand);
>
> void HandleVoldResponse(int aResponseCode, nsCWhitespaceTokenizer &aTokenizer);
>
> + static void UpdateMountLock(const nsACString &aVolumeName,
trailing ws
::: dom/system/gonk/nsVolume.cpp
@@ +140,5 @@
> +nsVolume::UpdateMountLock(const nsAString &aMountLockState)
> +{
> + // There are 3 states, unlocked, locked-background, and locked-foreground
> + // I figured it was easier to use neagtive logic and compare for unlocked.
> + UpdateMountLock(!aMountLockState.Equals(NS_LITERAL_STRING("unlocked")));
EqualsLiteral() ?
::: dom/system/gonk/nsVolumeService.cpp
@@ +43,5 @@
> +public:
> + NS_DECL_ISUPPORTS
> +
> + WakeLockCallback(nsVolumeService *aVolumeService)
> + :mVolumeService(aVolumeService)
Space after the :
@@ +72,5 @@
> + }
> +private:
> + // We're destructed by the nsVolumeService, so we use a bare pointer here
> + // to prevent cyclic references.
> + nsVolumeService *mVolumeService;
Raw pointers are dangerous. I have written a bunch of comments like that and usually end up being assigned topcrash bug a few months later.
Much rather you hold a strong reference and add a Shutdown() method and have the nsVolumeService call it.
Another approach -- which may work -- is just to have the nsVolumeService implement this listener.
@@ +110,5 @@
> FROM_HERE,
> NewRunnableFunction(ShutdownVolumeServiceIOThread));
> }
>
> +/* void BroadcastVolume(nsString volumeName) */
useless comment.
@@ +125,5 @@
> + nsCOMPtr<nsIObserverService> obs = GetObserverService();
> + NS_ENSURE_TRUE(obs, NS_NOINTERFACE);
> +
> + DBG("nsVolumeService::BroadcastVolume for '%s'", vol->NameStr());
> + nsString stateStr(NS_ConvertUTF8toUTF16(vol->StateStr()));
I think you want CopyUTF8toUTF16
@@ +194,5 @@
> + nsRefPtr<nsVolume> vol = mVolumeArray[volIndex];
> + nsString mountLockName;
> + vol->GetMountLockName(mountLockName);
> + if (mountLockName.Equals(aMountLockName)) {
> + vol->UpdateMountLock(aMountLockState);
can't we return early here?
@@ +274,5 @@
>
> + // Use CID rather than CONTRACTID so that we can cast the returned pointer
> + // to an nsVolumeService
> + NS_DEFINE_CID(volumeServiceCID, NS_VOLUMESERVICE_CID);
> + nsCOMPtr<nsVolumeService> vs(do_GetService(volumeServiceCID));
I would really rather you not have to do this. Could you instead, create a new interface that just has UpdateVolume(...) and then QI to it? Also.. ugh.
::: layout/build/nsLayoutModule.cpp
@@ +325,5 @@
>
> #ifdef MOZ_WIDGET_GONK
> NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIGeolocationProvider,
> GonkGPSGeolocationProvider::GetSingleton)
> +NS_GENERIC_FACTORY_CONSTRUCTOR(nsVolumeService) // after nsIPowerManagerService
I don't understand your comment.
Attachment #685950 -
Flags: feedback?(doug.turner) → feedback+
Comment 16•12 years ago
|
||
(In reply to Doug Turner (:dougt) from comment #15)
> ::: dom/ipc/ContentChild.cpp
> @@ +1094,5 @@
> > + // Remove warnings about unused arguments
> > + (void)aFsName;
> > + (void)aName;
> > + (void)aState;
> > + (void)aMountGeneration;
>
> does this work everywhere? not sure about some of the crap compilers we use.
unused << myUnusedVariable; is the recommended way to do this. (not "(void)"), from
https://mxr.mozilla.org/mozilla-central/source/xpcom/glue/unused.h
You just need to #include "mozilla/unused.h" and "using namespace mozilla;"
Assignee | ||
Comment 17•12 years ago
|
||
I realized that the files I submitted for feedback were missing a couple of files. Added in this patchset.
These will get merged together before submitting, but I figured I'd get feedback on these as well.
Attachment #688364 -
Flags: feedback?(doug.turner)
Assignee | ||
Comment 18•12 years ago
|
||
(In reply to Doug Turner (:dougt) from comment #15)
> @@ +72,5 @@
> > + }
> > +private:
> > + // We're destructed by the nsVolumeService, so we use a bare pointer here
> > + // to prevent cyclic references.
> > + nsVolumeService *mVolumeService;
>
> Raw pointers are dangerous. I have written a bunch of comments like that
> and usually end up being assigned topcrash bug a few months later.
>
> Much rather you hold a strong reference and add a Shutdown() method and have
> the nsVolumeService call it.
So that presumably implies listening for xpcom-shutdown and calling Shutdown at that time?
> Another approach -- which may work -- is just to have the nsVolumeService
> implement this listener.
I'll see if I can do that.
> @@ +110,5 @@
> > FROM_HERE,
> > NewRunnableFunction(ShutdownVolumeServiceIOThread));
> > }
> >
> > +/* void BroadcastVolume(nsString volumeName) */
>
> useless comment.
Perhaps. But that's what the IDL code generator puts as the suggested code style to use. If it's really all that useless then shouldn't the code generator be fixed?
> @@ +125,5 @@
> > + nsCOMPtr<nsIObserverService> obs = GetObserverService();
> > + NS_ENSURE_TRUE(obs, NS_NOINTERFACE);
> > +
> > + DBG("nsVolumeService::BroadcastVolume for '%s'", vol->NameStr());
> > + nsString stateStr(NS_ConvertUTF8toUTF16(vol->StateStr()));
>
> I think you want CopyUTF8toUTF16
So what's the difference?
NS_ConvertUTF8toUTF16 and ConvertUTF8toUTF16 both call NS_CStringtoUTF16
What I'm getting at, is this just a preferred convention? When should I use CopyUTF8toUTF16 versus using NS_ConvertUTF8toUTF16? I'm just trying to learn here, not justify.
> @@ +274,5 @@
> >
> > + // Use CID rather than CONTRACTID so that we can cast the returned pointer
> > + // to an nsVolumeService
> > + NS_DEFINE_CID(volumeServiceCID, NS_VOLUMESERVICE_CID);
> > + nsCOMPtr<nsVolumeService> vs(do_GetService(volumeServiceCID));
>
> I would really rather you not have to do this. Could you instead, create a
> new interface that just has UpdateVolume(...) and then QI to it? Also.. ugh.
I can add UpdateVolume to the IDL. It's just that it's an internal function and not something I want other users of the VolumeService to call.
> ::: layout/build/nsLayoutModule.cpp
> @@ +325,5 @@
> >
> > #ifdef MOZ_WIDGET_GONK
> > NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIGeolocationProvider,
> > GonkGPSGeolocationProvider::GetSingleton)
> > +NS_GENERIC_FACTORY_CONSTRUCTOR(nsVolumeService) // after nsIPowerManagerService
>
> I don't understand your comment.
I need the nsIPowerManagerService to be constructed before nsVolumeService is constructed (since the constructor of nsVolumeService does do_GetService(POWERMANAGERSERVICE_CONTRACTID). The only way that happens is if I move the location in the nsLayoutModule.cpp file.
Assignee | ||
Updated•12 years ago
|
Target Milestone: --- → B2G C3 (12dec-1jan)
Assignee | ||
Comment 19•12 years ago
|
||
The VolumeMountLock object, when locked, prevents the indicated volume (typically the sdcard) from being shared with the PC.
Attachment #674974 -
Attachment is obsolete: true
Attachment #685950 -
Attachment is obsolete: true
Attachment #688364 -
Attachment is obsolete: true
Attachment #688364 -
Flags: feedback?(doug.turner)
Attachment #692514 -
Flags: review?(doug.turner)
Assignee | ||
Comment 20•12 years ago
|
||
Modifies the updater to prefer using the sdcard. Also introduces the notion of a link file. The update meta-data is always stored in /data/local/updates/0 on the phone, and the update.link allows the actual patch file to live elsewhere (i.e. on the sdcard)
Attachment #692515 -
Flags: review?(marshall)
Assignee | ||
Comment 21•12 years ago
|
||
Modifies the updater to support update.link files. Modifies the UpdateDriver to prefer sdcard for B2G builds
Attachment #692516 -
Flags: review?(robert.bugzilla)
Assignee | ||
Comment 22•12 years ago
|
||
I submitted to try and I'm pasting the link before I know how good or bad it will be:
https://tbpl.mozilla.org/?tree=Try&rev=136a18bffb5e
Comment 23•12 years ago
|
||
Comment on attachment 692516 [details] [diff] [review]
Part 3 - Modify the updater to support update.link files
>diff --git a/toolkit/xre/nsUpdateDriver.cpp b/toolkit/xre/nsUpdateDriver.cpp
>index c6752b7..916a17a 100644
>--- a/toolkit/xre/nsUpdateDriver.cpp
>+++ b/toolkit/xre/nsUpdateDriver.cpp
>@@ -971,18 +971,27 @@ nsUpdateProcessor::ProcessUpdate(nsIUpdate* aUpdate)
>
> NS_ENSURE_ARG_POINTER(aUpdate);
>
> nsAutoCString binPath;
> nsXREDirProvider* dirProvider = nsXREDirProvider::GetSingleton();
> if (dirProvider) { // Normal code path
> // Check for and process any available updates
> bool persistent;
>- nsresult rv = dirProvider->GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
>- getter_AddRefs(updRoot));
>+ nsresult rv = NS_OK;
>+#ifdef MOZ_WIDGET_GONK
>+ // Check in the sdcard for updates first, since that's our preferred
>+ // download location.
>+ rv = dirProvider->GetFile("UpdArchD", &persistent,
>+ getter_AddRefs(updRoot));
>+#endif
>+ if (NS_FAILED(rv)) {
looks like this will never happen for non gonk.
could you run these patches through try as well?
>+ rv = dirProvider->GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
>+ getter_AddRefs(updRoot));
>+ }
> // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
> if (NS_FAILED(rv))
> updRoot = dirProvider->GetAppDir();
>
> greDir = dirProvider->GetGREDir();
> appDir = dirProvider->GetAppDir();
> appVersion = gAppData->version;
> argc = gRestartArgc;
>--
>1.7.9.5
>
Assignee | ||
Comment 24•12 years ago
|
||
(In reply to Robert Strong [:rstrong] (do not email) from comment #23)
...snip...
> >+ nsresult rv = NS_OK;
> >+#ifdef MOZ_WIDGET_GONK
> >+ // Check in the sdcard for updates first, since that's our preferred
> >+ // download location.
> >+ rv = dirProvider->GetFile("UpdArchD", &persistent,
> >+ getter_AddRefs(updRoot));
> >+#endif
> >+ if (NS_FAILED(rv)) {
> looks like this will never happen for non gonk.
Doh.
> could you run these patches through try as well?
Yep - since some of these changes affect other platforms, I really need to have clean try runs before I can push these.
Assignee | ||
Comment 25•12 years ago
|
||
OK - After a couple of tweaks - (The contents of RecvBroadcastVolume needed an ifdef on MOZ_WIDGET_GONK), and a fix to initialize rv correctly (comment 24), this is the try run:
https://tbpl.mozilla.org/?tree=Try&rev=b15721fc3252
My try run was based on revision 116114:
https://tbpl.mozilla.org/?tree=Mozilla-Inbound&rev=a0e351bde946
Assignee | ||
Comment 26•12 years ago
|
||
Addresses the initialization of rv in comment 24
Try run including this change is mentioned in comment 25
Attachment #692516 -
Attachment is obsolete: true
Attachment #692516 -
Flags: review?(robert.bugzilla)
Attachment #692996 -
Flags: review?(robert.bugzilla)
Comment 27•12 years ago
|
||
Comment on attachment 692514 [details] [diff] [review]
Part 1 - Add a VolumeMountLock object
Review of attachment 692514 [details] [diff] [review]:
-----------------------------------------------------------------
::: dom/ipc/ContentChild.h
@@ +185,5 @@
> virtual bool RecvFilePathUpdate(const nsString& type, const nsString& path, const nsCString& reason);
> + virtual bool RecvFileSystemUpdate(const nsString& aFsName,
> + const nsString& aName,
> + const int32_t& aState,
> + const int32_t &aMountGeneration);
space after & and before the parameter name.
::: dom/ipc/ContentParent.cpp
@@ +234,1 @@
> }
What was this change? oh, splinter..
@@ +1048,5 @@
> return true;
> }
>
> +bool
> +ContentParent::RecvBroadcastVolume(const nsString &aVolumeName)
Space after '&', not before
@@ +1052,5 @@
> +ContentParent::RecvBroadcastVolume(const nsString &aVolumeName)
> +{
> + nsresult rv;
> + nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
> + NS_ENSURE_SUCCESS(rv, true);
Just set on vs not being null.
::: dom/ipc/ContentParent.h
@@ +308,5 @@
>
> virtual bool RecvAudioChannelRegisterType(const AudioChannelType& aType);
> virtual bool RecvAudioChannelUnregisterType(const AudioChannelType& aType);
>
> + virtual bool RecvBroadcastVolume(const nsString &volumeName);
Space after &, not before.
::: dom/ipc/PContent.ipdl
@@ +326,5 @@
>
> FilePathUpdate(nsString type, nsString filepath, nsCString reasons);
>
> + FileSystemUpdate(nsString fsName, nsString mountPoint, int32_t fsState,
> + int32_t mountInstance);
Shouldn't this be called 'mountGeneration' not 'mountInstance'?
::: dom/system/gonk/AutoMounter.cpp
@@ +406,5 @@
> + (int)vol->IsMountLocked());
> + } else {
> + LOG("UpdateState: Volume %s is %s and %s", vol->NameStr(), vol->StateStr(),
> + vol->MediaPresent() ? "inserted" : "missing");
> + }
Can you wrap this entire block in whatever #define that LOG uses?
@@ +421,5 @@
> + // The volume is currently locked, so leave it in the mounted
> + // state.
> + DBG("UpdateState: Mounted volume %s is locked, leaving",
> + vol->NameStr());
> + break;
could you use return here? I do not think you need to do anything else int his method, right? (not enough context to see in this patch, but the next block uses return).
::: dom/system/gonk/Volume.cpp
@@ +36,5 @@
> +// 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.
So, we only update the generation number on the main thread, and we are guarding that with assertions, right?
@@ +56,5 @@
> : mMediaPresent(true),
> mState(nsIVolume::STATE_INIT),
> + mName(aName),
> + mMountGeneration(-1),
> + mMountLocked(true) // Needs to agree with nsVolume::nsVolume
i have seen a different style that is more popular:
: mMediaPresent(true)
, mState(nsIVolume::STATE_INIT)
, ......
@@ +98,4 @@
>
> void
> Volume::SetState(Volume::STATE aNewState)
> {
This can only happen on the main thread. Please add an assertion.
@@ +191,5 @@
> +void
> +Volume::UpdateMountLock(const nsACString &aVolumeName,
> + const int32_t &aMountGeneration,
> + const bool &aMountLocked)
> +{
This also can only happen on the main thread, right?
::: dom/system/gonk/VolumeServiceIOThread.cpp
@@ +12,5 @@
> namespace mozilla {
> namespace system {
>
> +VolumeServiceIOThread::VolumeServiceIOThread(nsVolumeService *aVolumeService)
> + : mVolumeService(aVolumeService)
So the IOThread has a strong reference to the volume service. How do we make sure that we release the volume service -- do we kill this IO thread at shutdown?
@@ +62,4 @@
> }
> }
>
> static RefPtr<VolumeServiceIOThread> sVolumeServiceIOThread;
shouldn't you be using StaticRefPtr<T>
@@ +69,3 @@
> {
> MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
> + sVolumeServiceIOThread = new VolumeServiceIOThread(aVolumeService);
Shouldn't you assert that sVolumeServiceIOThread is null before calling new?
::: dom/system/gonk/VolumeServiceIOThread.h
@@ +22,5 @@
> public Volume::EventObserver,
> public RefCounted<VolumeServiceIOThread>
> {
> public:
> + VolumeServiceIOThread(nsVolumeService *aVolumeService);
space between the * and the type
::: dom/system/gonk/nsIVolumeMountLock.idl
@@ +7,5 @@
> +[scriptable, uuid(44449f34-5ca1-4aff-bce6-22c79263de24)]
> +interface nsIVolumeMountLock : nsISupports
> +{
> + void unlock();
> +};
Just move this interface into nsIVolume.idl. Purist might complain, but nsIVolume.idl already has CID's listed in it... so wahtever.
::: dom/system/gonk/nsVolume.cpp
@@ +55,5 @@
> return NS_OK;
> }
>
> +NS_IMETHODIMP nsVolume::GetMountGeneration(int32_t *aMountGeneration)
> +{
type& aName
@@ +60,5 @@
> + *aMountGeneration = mMountGeneration;
> + return NS_OK;
> +}
> +
> +NS_IMETHODIMP nsVolume::GetMountLockName(nsAString &aMountLockName)
type& aName
@@ +104,5 @@
> + LOG("nsVolume: %s state %s", NameStr(), StateStr());
> +}
> +
> +void nsVolume::Set(const nsVolume *aVolume)
> +{
not an operator= ?
::: dom/system/gonk/nsVolume.h
@@ +26,5 @@
> nsVolume(const Volume *aVolume);
>
> + // This constructor is used by ContentChild::RecvFileSystemUpdate
> + nsVolume(const nsAString &aName, const nsAString &aMountPoint,
> + const int32_t &aState, const int32_t &aMountGeneration)
type& aName
::: dom/system/gonk/nsVolumeMountLock.h
@@ +28,5 @@
> +{
> +public:
> + NS_DECL_ISUPPORTS
> + NS_DECL_NSIVOLUMEMOUNTLOCK
> +
Why aren't you using NS_DECL_NSIOBSERVER instead?
@@ +30,5 @@
> + NS_DECL_ISUPPORTS
> + NS_DECL_NSIVOLUMEMOUNTLOCK
> +
> + // Returns a strong reference to the VolumeMountLock instance for the indicated
> + // volume.
drop this comment. it is more confusing (to me at least) than just the method name. :)
::: dom/system/gonk/nsVolumeService.h
@@ +35,4 @@
>
> nsVolumeService();
>
> + static nsVolumeService *GetSingleton();
I like returning already_AddRefed<> because then users tend not to screw up.
@@ +43,4 @@
> already_AddRefed<nsVolume> FindVolumeByName(const nsAString &aName);
> already_AddRefed<nsVolume> FindAddVolumeByName(const nsAString &aName);
> void UpdateVolume(const nsVolume *aVolume);
> + void UpdateVolumeIOThread(const Volume *aVolume);
type* aName
@@ +49,5 @@
> ~nsVolumeService();
>
> + nsVolume::Array mVolumeArray;
> +
> + static StaticRefPtr<nsVolumeService> sSingleton;
one space between the > and s
::: layout/build/nsLayoutModule.cpp
@@ +328,5 @@
> NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIGeolocationProvider,
> GonkGPSGeolocationProvider::GetSingleton)
> +// Since the nsVolumeService constructor calls into nsIPowerManagerService,
> +// we need it to be constructed sometime after nsIPowerManagerService.
> +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsVolumeService,
I do not understand this comment. Is that really true? What is the build error if you just leave this alone?
::: layout/build/nsLayoutStatics.cpp
@@ +353,3 @@
> nsCORSListenerProxy::Shutdown();
>
> nsIPresShell::ReleaseStatics();
There is some trailing white space in this file. Mind cleaning it up while you are here? M-x delete-trailing-whitespace
Assignee | ||
Comment 28•12 years ago
|
||
(In reply to Doug Turner (:dougt) from comment #27)
> ::: dom/ipc/ContentParent.cpp
> @@ +234,1 @@
> > }
>
> What was this change? oh, splinter..
Oh that was an indentation change I had done in a previous patch that wasn't consistent with the rest of the file. I noticed it while doing this patch and fixed it.
> @@ +1052,5 @@
> > +ContentParent::RecvBroadcastVolume(const nsString &aVolumeName)
> > +{
> > + nsresult rv;
> > + nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
> > + NS_ENSURE_SUCCESS(rv, true);
>
> Just set on vs not being null.
I don't understand this comment.
Or did you mean that I should do:
if (!vs) {
vs->BroadcastVolume(aVolumeName);
}
return true;
> ::: dom/ipc/PContent.ipdl
> @@ +326,5 @@
> >
> > FilePathUpdate(nsString type, nsString filepath, nsCString reasons);
> >
> > + FileSystemUpdate(nsString fsName, nsString mountPoint, int32_t fsState,
> > + int32_t mountInstance);
>
> Shouldn't this be called 'mountGeneration' not 'mountInstance'?
Yep - I had renamed it along the way and missed that one.
> ::: dom/system/gonk/AutoMounter.cpp
> @@ +406,5 @@
> > + (int)vol->IsMountLocked());
> > + } else {
> > + LOG("UpdateState: Volume %s is %s and %s", vol->NameStr(), vol->StateStr(),
> > + vol->MediaPresent() ? "inserted" : "missing");
> > + }
>
> Can you wrap this entire block in whatever #define that LOG uses?
LOG doesn't use a macro (i.e. this LOG is always done) and its quite intentional. It's a very low frequency log statment, once per state change of the volume (which is a few log lines per SD card insertion/removal.
> @@ +421,5 @@
> > + // The volume is currently locked, so leave it in the mounted
> > + // state.
> > + DBG("UpdateState: Mounted volume %s is locked, leaving",
> > + vol->NameStr());
> > + break;
>
> could you use return here? I do not think you need to do anything else int
> his method, right? (not enough context to see in this patch, but the next
> block uses return).
Hmm. For a single volume, either one works. For multiple volumes, this needs to be a break, so the returns are incorrect.
> ::: dom/system/gonk/Volume.cpp
> @@ +36,5 @@
> > +// 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.
>
> So, we only update the generation number on the main thread, and we are
> guarding that with assertions, right?
I can throw more assertions in. nsVolumeXxx is all main thread, and VolumeXxx is all IOThread.
> @@ +56,5 @@
> > : mMediaPresent(true),
> > mState(nsIVolume::STATE_INIT),
> > + mName(aName),
> > + mMountGeneration(-1),
> > + mMountLocked(true) // Needs to agree with nsVolume::nsVolume
>
> i have seen a different style that is more popular:
>
> : mMediaPresent(true)
> , mState(nsIVolume::STATE_INIT)
> , ......
Yeah and I cringe every time I see it.
> @@ +98,4 @@
> >
> > void
> > Volume::SetState(Volume::STATE aNewState)
> > {
>
> This can only happen on the main thread. Please add an assertion.
Actually, this can ONLY happen on the IOThread. Volume methods are all IOThread (nsVolume methods are all MainThread).
SetState is a private method. I chose to put assertions in the API entry points that outsiders can use. If you want I can add an assertion in every single Volume::Xxx function to verify that its on the IOThread and add an assertion in every single nsVolume:Xxx function to verify that its on the MainThread, but that seems like overkill to me.
> @@ +191,5 @@
> > +void
> > +Volume::UpdateMountLock(const nsACString &aVolumeName,
> > + const int32_t &aMountGeneration,
> > + const bool &aMountLocked)
> > +{
>
> This also can only happen on the main thread, right?
This is a Volume method, so it should only happen on the IOThread.
> ::: dom/system/gonk/VolumeServiceIOThread.cpp
> @@ +12,5 @@
> > namespace mozilla {
> > namespace system {
> >
> > +VolumeServiceIOThread::VolumeServiceIOThread(nsVolumeService *aVolumeService)
> > + : mVolumeService(aVolumeService)
>
> So the IOThread has a strong reference to the volume service. How do we
> make sure that we release the volume service -- do we kill this IO thread at
> shutdown?
nsVolumeService::Shutdown posts a call to ShutdownVolumeServiceIOThread
>
> @@ +62,4 @@
> > }
> > }
> >
> > static RefPtr<VolumeServiceIOThread> sVolumeServiceIOThread;
>
> shouldn't you be using StaticRefPtr<T>
>
> @@ +69,3 @@
> > {
> > MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
> > + sVolumeServiceIOThread = new VolumeServiceIOThread(aVolumeService);
>
> Shouldn't you assert that sVolumeServiceIOThread is null before calling new?
>
> ::: dom/system/gonk/VolumeServiceIOThread.h
> @@ +22,5 @@
> > public Volume::EventObserver,
> > public RefCounted<VolumeServiceIOThread>
> > {
> > public:
> > + VolumeServiceIOThread(nsVolumeService *aVolumeService);
>
> space between the * and the type
>
> ::: dom/system/gonk/nsIVolumeMountLock.idl
> @@ +7,5 @@
> > +[scriptable, uuid(44449f34-5ca1-4aff-bce6-22c79263de24)]
> > +interface nsIVolumeMountLock : nsISupports
> > +{
> > + void unlock();
> > +};
>
> Just move this interface into nsIVolume.idl. Purist might complain, but
> nsIVolume.idl already has CID's listed in it... so wahtever.
>
> ::: dom/system/gonk/nsVolume.cpp
> @@ +55,5 @@
> > return NS_OK;
> > }
> >
> > +NS_IMETHODIMP nsVolume::GetMountGeneration(int32_t *aMountGeneration)
> > +{
>
> type& aName
>
> @@ +60,5 @@
> > + *aMountGeneration = mMountGeneration;
> > + return NS_OK;
> > +}
> > +
> > +NS_IMETHODIMP nsVolume::GetMountLockName(nsAString &aMountLockName)
>
> type& aName
I don't use that convention in these files. The & belongs with the variable name and not the type.
i.e. If you do nsAString& a, b;
then b is NOT a reference.
Coding it like
nsAString &a, b;
makes it clear that a is an nsString reference and b is an nsString.
If I fix this one, I'll need to fix the other 300 occurrences in these files to make them consistent.
> @@ +104,5 @@
> > + LOG("nsVolume: %s state %s", NameStr(), StateStr());
> > +}
> > +
> > +void nsVolume::Set(const nsVolume *aVolume)
> > +{
>
> not an operator= ?
It's called in exactly one place in the code, so I didn't think it warranted an operator =
> ::: dom/system/gonk/nsVolumeMountLock.h
> @@ +28,5 @@
> > +{
> > +public:
> > + NS_DECL_ISUPPORTS
> > + NS_DECL_NSIVOLUMEMOUNTLOCK
> > +
>
> Why aren't you using NS_DECL_NSIOBSERVER instead?
Technically, I should probably have NS_DECL_NSIOBSERVER as well, and remove the prototype for the Observe method.
>
> @@ +30,5 @@
> > + NS_DECL_ISUPPORTS
> > + NS_DECL_NSIVOLUMEMOUNTLOCK
> > +
> > + // Returns a strong reference to the VolumeMountLock instance for the indicated
> > + // volume.
>
> drop this comment. it is more confusing (to me at least) than just the
> method name. :)
Yeah - I was inherting from ISupportsWeakReference so I didn't want people to think it might be returning a weak reference.
> ::: dom/system/gonk/nsVolumeService.h
> @@ +35,4 @@
> >
> > nsVolumeService();
> >
> > + static nsVolumeService *GetSingleton();
>
> I like returning already_AddRefed<> because then users tend not to screw up.
All the examples that use NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR that I could find return a bare pointer.
I also verified that using already_AddRefed can be used here, so I can change it.
> ::: layout/build/nsLayoutModule.cpp
> @@ +328,5 @@
> > NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIGeolocationProvider,
> > GonkGPSGeolocationProvider::GetSingleton)
> > +// Since the nsVolumeService constructor calls into nsIPowerManagerService,
> > +// we need it to be constructed sometime after nsIPowerManagerService.
> > +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsVolumeService,
>
> I do not understand this comment. Is that really true? What is the build
> error if you just leave this alone?
There is no build error. However pmService will be assigned null in the nsVolumeService constructor when I do:
nsCOMPtr<nsIPowerManagerService> pmService =
do_GetService(POWERMANAGERSERVICE_CONTRACTID);
If nsIVolumeService is constructed after nsIPowerManager, then pmService is assigned properly.
I talked with Kyle Huey and he said that it was fine to call do_GetService from my constructor as long as there weren't any circular references (and Kyle said that this was done all the time)
> ::: layout/build/nsLayoutStatics.cpp
> @@ +353,3 @@
> > nsCORSListenerProxy::Shutdown();
> >
> > nsIPresShell::ReleaseStatics();
>
> There is some trailing white space in this file. Mind cleaning it up while
> you are here? M-x delete-trailing-whitespace
Sure. I don't use emacs, but I have Edit->Other->Remove Trailing Whitespace :)
I actually have a utiltiy I wrote for checking line endings (and I considered trailing whitespace a type of line ending)
https://github.com/dhylands/projects/tree/master/utils/src/CountLineEndings
Assignee | ||
Comment 29•12 years ago
|
||
Address review comments
Attachment #692514 -
Attachment is obsolete: true
Attachment #692514 -
Flags: review?(doug.turner)
Attachment #693195 -
Flags: review?(doug.turner)
Assignee | ||
Comment 30•12 years ago
|
||
This patchset should just contain whitespace changes.
Attachment #693196 -
Flags: review?(doug.turner)
Comment 31•12 years ago
|
||
Comment on attachment 692996 [details] [diff] [review]
Part 3 (v2) - Modify the updater to support update.link files
Brian, could you take a look at this as well? Thanks
Attachment #692996 -
Flags: review?(netzen)
Comment 32•12 years ago
|
||
Comment on attachment 692996 [details] [diff] [review]
Part 3 (v2) - Modify the updater to support update.link files
Review of attachment 692996 [details] [diff] [review]:
-----------------------------------------------------------------
Look good to me. I don't see any issues security wise as far as MAR verification goes because we verify the signature after that path is obtained. So even if someone staged a .link file it wouldn't help them.
::: toolkit/mozapps/update/updater/updater.cpp
@@ +2074,5 @@
> + *fileName = NS_T('\0');
> + return READ_ERROR;
> + }
> + dataFileName[bytesRead] = '\0';
> + if ((bytesRead > 0 ) && (dataFileName[bytesRead-1] == '\n')) {
do another similar block in addition to this for '\r'
Which would cover \n, \r and \r\n
@@ +2081,5 @@
> + dataFileName[bytesRead] = '\0';
> + }
> +
> +#if defined(XP_WIN)
> + size_t charsRequired = mbstowcs(NULL, dataFileName, 0);
Maybe use MultiByteToWideChar so you have UTF8 support for proper unicode conversion:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072%28v=vs.85%29.aspx
Although I don't think we need this functionality on Windows so I'm fine if you want to keep it as is.
::: toolkit/xre/nsUpdateDriver.cpp
@@ +990,5 @@
> + nsresult rv = NS_ERROR_FAILURE; // Take the NS_FAILED path when non-GONK
> +#ifdef MOZ_WIDGET_GONK
> + // Check in the sdcard for updates first, since that's our preferred
> + // download location.
> + rv = dirProvider->GetFile("UpdArchD", &persistent,
Maybe check with someone else if this is the correct dir key
Attachment #692996 -
Flags: review?(netzen) → feedback+
Comment 33•12 years ago
|
||
Comment on attachment 693195 [details] [diff] [review]
Part 1 - (v2) Add a VolumeMountLock object
Review of attachment 693195 [details] [diff] [review]:
-----------------------------------------------------------------
I think you should add more thread assertions in Volume::... but not going to block this on that. otherwises lgtm
Attachment #693195 -
Flags: review?(doug.turner) → review+
Comment 34•12 years ago
|
||
Comment on attachment 693196 [details] [diff] [review]
Part 4 - Fix refs and ptrs (change type &var to type& var)
consistency is good. rs=me
Attachment #693196 -
Flags: review?(doug.turner) → review+
Assignee | ||
Comment 36•12 years ago
|
||
Make changes as per bbondy's review comments (strip trailing CR as well as trailing NL).
Also talked with bbondy on IRC and revised GetUpdateFilename so that looking for the update.link file is gonk-only.
Attachment #692996 -
Attachment is obsolete: true
Attachment #692996 -
Flags: review?(robert.bugzilla)
Assignee | ||
Comment 37•12 years ago
|
||
Comment on attachment 694094 [details] [diff] [review]
Part 3 (v3) - Modify the updater to support update.link files
So now it looks like all of the changes in this patchset are gonk specific.
Attachment #694094 -
Flags: review?(robert.bugzilla)
Assignee | ||
Comment 38•12 years ago
|
||
Added definition of UpdArchD in nsXULAppApi.h and adjusted nsUpdateDriver.cpp to use it.
Attachment #694094 -
Attachment is obsolete: true
Attachment #694094 -
Flags: review?(robert.bugzilla)
Attachment #694126 -
Flags: review?(robert.bugzilla)
Reporter | ||
Comment 39•12 years ago
|
||
Comment on attachment 692515 [details] [diff] [review]
Part 2 - Js changes to the updater
Review of attachment 692515 [details] [diff] [review]:
-----------------------------------------------------------------
Great work! Just some nits :)
::: b2g/components/DirectoryProvider.js
@@ +158,5 @@
> + return dir;
> + }
> + // updates/0 is either a file or isn't writable. In either case we
> + // can't use it.
> + return null;
nit: should we log or when updates/0 isn't a directory / writable here?
::: toolkit/mozapps/update/nsUpdateService.js
@@ +982,5 @@
> catch (e) {
> LOG("cleanUpUpdatesDir - failed to remove file " + f.path);
> }
> }
> + releaseSDCardMountLock();
should this be surrounded by #ifdef MOZ_WIDGET_GONK? also below on line 2887 and 3236
Attachment #692515 -
Flags: review?(marshall) → review+
Assignee | ||
Comment 40•12 years ago
|
||
(In reply to Marshall Culpepper [:marshall_law] from comment #39)
> Comment on attachment 692515 [details] [diff] [review]
> Part 2 - Js changes to the updater
>
> Review of attachment 692515 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> Great work! Just some nits :)
>
> ::: b2g/components/DirectoryProvider.js
> @@ +158,5 @@
> > + return dir;
> > + }
> > + // updates/0 is either a file or isn't writable. In either case we
> > + // can't use it.
> > + return null;
>
> nit: should we log or when updates/0 isn't a directory / writable here?
Sure - I can add that.
> ::: toolkit/mozapps/update/nsUpdateService.js
> @@ +982,5 @@
> > catch (e) {
> > LOG("cleanUpUpdatesDir - failed to remove file " + f.path);
> > }
> > }
> > + releaseSDCardMountLock();
>
> should this be surrounded by #ifdef MOZ_WIDGET_GONK? also below on line 2887
> and 3236
I put an #ifdef inside the releaseSDCardMountLock function so that we didn't have to clutter up the callers (i.e. releaseSDCardMountLock is an empty function for non-gonk)
Assignee | ||
Comment 41•12 years ago
|
||
I discovered my missing asserts in another source tree (I guess I accidentally edited the wrong file).
Attachment #695056 -
Flags: review?(doug.turner)
Comment 42•12 years ago
|
||
Comment on attachment 695056 [details] [diff] [review]
Part 5 - Add the missing ASSERTs that Doug wanted
Review of attachment 695056 [details] [diff] [review]:
-----------------------------------------------------------------
::: dom/system/gonk/Volume.cpp
@@ +64,5 @@
>
> void
> Volume::SetMediaPresent(bool aMediaPresent)
> {
> + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default));
Extra ')' at the stmt. plz fix them all.
Attachment #695056 -
Flags: review?(doug.turner) → review+
Assignee | ||
Comment 43•12 years ago
|
||
(In reply to Doug Turner (:dougt) from comment #42)
> Comment on attachment 695056 [details] [diff] [review]
> Part 5 - Add the missing ASSERTs that Doug wanted
>
> Review of attachment 695056 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> ::: dom/system/gonk/Volume.cpp
> @@ +64,5 @@
> >
> > void
> > Volume::SetMediaPresent(bool aMediaPresent)
> > {
> > + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default));
>
> Extra ')' at the stmt. plz fix them all.
I was just testing to see if you were paying attention :)
My build failed as soon as I tried it, but I had already put the patch up for review, so I decided to leave it and see if you'd notice.
Updated•12 years ago
|
Whiteboard: [LOE:S] → [LOE:S][needs review robstrong]
Updated•12 years ago
|
Target Milestone: B2G C3 (12dec-1jan) → B2G C4 (2jan on)
Updated•12 years ago
|
Attachment #694126 -
Flags: review?(robert.bugzilla) → review+
Need an updated part 5.
Keywords: checkin-needed
Whiteboard: [LOE:S][needs review robstrong] → [LOE:S]
Assignee | ||
Comment 45•12 years ago
|
||
I was planning on landing this later today. I was going to do a little bit of cleanup (based on Marshall's comments).
I have the updated patch for part 5 in my tree already
Updated•12 years ago
|
Keywords: checkin-needed
Assignee | ||
Comment 46•12 years ago
|
||
https://hg.mozilla.org/integration/mozilla-inbound/rev/599c37ed628c
https://hg.mozilla.org/integration/mozilla-inbound/rev/02a3fbcf2ac9
https://hg.mozilla.org/integration/mozilla-inbound/rev/71f66edcab12
https://hg.mozilla.org/integration/mozilla-inbound/rev/f3db472234e9
https://hg.mozilla.org/integration/mozilla-inbound/rev/6737ce4d3ce6
Comment 47•12 years ago
|
||
Backed out in https://hg.mozilla.org/integration/mozilla-inbound/rev/95c4247fc5b7 - took a while to see, what with one thing and another, but you were failing 10 update xpcshell emulator tests, a la https://tbpl.mozilla.org/php/getParsedLog.php?id=18580148&tree=Mozilla-Inbound
Updated•12 years ago
|
Version: unspecified → Trunk
Assignee | ||
Comment 48•12 years ago
|
||
So far, I've tried running xpcshell locally, but I can't reproduce the failure on inbound.
I also pushed to try again, just the xpcshell test, but it's been sitting in the queue for 16 hours and still hasn't run.
https://tbpl.mozilla.org/?tree=Try&rev=e35c980bb797
Updated•12 years ago
|
Whiteboard: [LOE:S] → [underway but landing blocked by 813770]
Assignee | ||
Comment 49•12 years ago
|
||
Attachment #700309 -
Flags: review?(marshall)
Assignee | ||
Comment 50•12 years ago
|
||
Attachment #700312 -
Flags: review?(jduell.mcbugs)
Assignee | ||
Comment 51•12 years ago
|
||
It turns out that we get different error codes when the mar file gets stored to sdcard versus /data for part 12 of this test.
Bug 82858 was filed to investigate this further.
Assignee | ||
Updated•12 years ago
|
Attachment #700313 -
Flags: review?(jst)
Comment 52•12 years ago
|
||
Comment on attachment 700312 [details] [diff] [review]
Fix nsIncrementalDownload to work on sdcard for B2G
Review of attachment 700312 [details] [diff] [review]:
-----------------------------------------------------------------
::: netwerk/base/src/nsIncrementalDownload.cpp
@@ +45,5 @@
> +#if defined(MOZ_WIDGET_GONK)
> + // The sdcard on a B2G phone looks like:
> + // d---rwx--- system sdcard_rw 1970-01-01 01:00:00 sdcard
> + // On the emulator, xpcshell fails when using 0600 mode to open the file,
> + // and 0660 works.
Get rid of whitespace at end of line here, and in blank line after this.
Attachment #700312 -
Flags: review?(jduell.mcbugs) → review+
Reporter | ||
Updated•12 years ago
|
Attachment #700309 -
Flags: review?(marshall) → review+
Comment 53•12 years ago
|
||
Comment on attachment 700313 [details] [diff] [review]
Fix test_0030_general.js to work when downloaded file goes to sdcard.
Looks good, r=jst
Attachment #700313 -
Flags: review?(jst) → review+
Assignee | ||
Comment 54•12 years ago
|
||
https://hg.mozilla.org/integration/mozilla-inbound/rev/eea4fefd010b
https://hg.mozilla.org/integration/mozilla-inbound/rev/82c54850f723
https://hg.mozilla.org/integration/mozilla-inbound/rev/4dabceec29a3
https://hg.mozilla.org/integration/mozilla-inbound/rev/0e777d664763
https://hg.mozilla.org/integration/mozilla-inbound/rev/9d9ec6237d95
https://hg.mozilla.org/integration/mozilla-inbound/rev/77d3c4a0afb6
https://hg.mozilla.org/integration/mozilla-inbound/rev/22991fd4bcd8
https://hg.mozilla.org/integration/mozilla-inbound/rev/2c54fb92091a
Updated•12 years ago
|
Whiteboard: [underway but landing blocked by 813770]
Comment 55•12 years ago
|
||
https://hg.mozilla.org/releases/mozilla-b2g18/rev/0ea5178e34fe
https://hg.mozilla.org/releases/mozilla-b2g18/rev/7d51207a310d
https://hg.mozilla.org/releases/mozilla-b2g18/rev/09d6df5a6c01
https://hg.mozilla.org/releases/mozilla-b2g18/rev/8f5247c3cf65
https://hg.mozilla.org/releases/mozilla-b2g18/rev/312453436ba5
https://hg.mozilla.org/releases/mozilla-b2g18/rev/1381256cd663
https://hg.mozilla.org/releases/mozilla-b2g18/rev/ac1d59f82cab
https://hg.mozilla.org/releases/mozilla-b2g18/rev/cc8240cc2d1f
Status: NEW → RESOLVED
Closed: 12 years ago
Resolution: --- → FIXED
Updated•12 years ago
|
Comment 56•12 years ago
|
||
https://hg.mozilla.org/mozilla-central/rev/eea4fefd010b
https://hg.mozilla.org/mozilla-central/rev/82c54850f723
https://hg.mozilla.org/mozilla-central/rev/4dabceec29a3
https://hg.mozilla.org/mozilla-central/rev/0e777d664763
https://hg.mozilla.org/mozilla-central/rev/9d9ec6237d95
https://hg.mozilla.org/mozilla-central/rev/77d3c4a0afb6
https://hg.mozilla.org/mozilla-central/rev/22991fd4bcd8
https://hg.mozilla.org/mozilla-central/rev/2c54fb92091a
Updated•12 years ago
|
status-firefox21:
--- → fixed
You need to log in
before you can comment on or make changes to this bug.
Description
•