Experimental Feature: Quiet Background Processes UI and WinRT server#2202
Experimental Feature: Quiet Background Processes UI and WinRT server#2202jsidewhite wants to merge 1 commit intomainfrom
Conversation
Adding the "Enable 'Quiet Background Processes'" experimental feature to Dev Home. It's a toggle that is enabled similarly to Focus Assist mode, that expires after a period of time. When you enable it/toggle it on via the UI, Dev Home will call into the OS to enable quieting down background services (e.g. Search Indexer). * Requires 'Admin' * Requires OS build 26024 or higher
| </data> | ||
| <data name="QuietBackgroundProcessesExperiment_Description" xml:space="preserve"> | ||
| <value>Silence and track background processes that may hinder device performance</value> | ||
| </data> |
There was a problem hiding this comment.
we usually add a comment to the resource so the localization folks have more context.
|
|
||
| mimetype: application/x-microsoft.net.object.bytearray.base64 | ||
| value : The object must be serialized into a byte array | ||
| : using a System.ComponentModel.TypeConverter |
There was a problem hiding this comment.
we can remove these comments
| <value>This feature can be activated for 2 hours.</value> | ||
| </data> | ||
| <data name="QuietBackgroundProcessesExplanation.Header" xml:space="preserve"> | ||
| <value>Quiet background processes beta feature description</value> |
There was a problem hiding this comment.
quick question, did a content writer right these descriptions?
| _zero = new TimeSpan(0, 0, 0); | ||
|
|
||
| var osVersion = Environment.OSVersion; | ||
| _validOsVersion = osVersion.Version.Build >= 26024; |
There was a problem hiding this comment.
are there any plans to backport it? I remember for Dev Drives we had to get the storage folks to write an api that we can check against since version checking wasn't ideal.
|
|
||
| private string _timeLeft = string.Empty; | ||
|
|
||
| public string TimeLeft |
There was a problem hiding this comment.
checkout https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/ its used everywhere in DevHome and by adding attributes about a field it auto generates this code for you. E.g
There was a problem hiding this comment.
Using [ObservableProperty takes a bit of extra work at first, but the payoff is less code in code-behind.
| </controls:SettingsCard> | ||
|
|
||
| <!-- Hyperlinks --> | ||
| <!-- |
| // Copyright (c) Microsoft Corporation and Contributors | ||
| // Licensed under the MIT license. | ||
|
|
||
| namespace DevHome.QuietBackgroundProcesses |
There was a problem hiding this comment.
whats the plan for this idl? Is this a Dev Home internal thing or do we expect people in the public to want to use this too? Just curious is all. I thought with c++/winrt we can use the implements stuct. Or does that not work here so we need to use an idl file?
| // Destruct time window on sepearate thread because its destructor may take time to end (the std::future member is blocking) | ||
| // | ||
| // (Make a new discard thread and chain the existing one to it) | ||
| g_discardThread = std::thread([timer = std::move(timer), previousThread = std::move(previousThread)]() mutable { |
There was a problem hiding this comment.
do we care that std::thread can throw?
| previousThread = std::move(g_discardThread); | ||
| } | ||
|
|
||
| // Destruct time window on sepearate thread because its destructor may take time to end (the std::future member is blocking) |
There was a problem hiding this comment.
| // Destruct time window on sepearate thread because its destructor may take time to end (the std::future member is blocking) | |
| // Destruct time window on separate thread because its destructor may take time to end (the std::future member is blocking) |
|
|
||
| using CallbackFunction = void (*)(); | ||
|
|
||
| class Timer |
There was a problem hiding this comment.
could we have used a periodic timer instead of this timer class? https://learn.microsoft.com/en-us/uwp/api/windows.system.threading.threadpooltimer.createperiodictimer?view=winrt-22621
| <PrivateAssets>all</PrivateAssets> | ||
| <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> | ||
| </PackageReference> | ||
| <PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.4" /> |
There was a problem hiding this comment.
You shouldn't need to add this since we get it for free from DevHome.Common.
| <ExcludeAssets>contentFiles</ExcludeAssets> | ||
| </PackageReference> | ||
| </ItemGroup> | ||
|
|
There was a problem hiding this comment.
Nit: put this blank line back.
| "icon": "ea86" | ||
| } | ||
| /*, | ||
| , |
There was a problem hiding this comment.
Nit: put this comma on line above.
| "ExperimentalFeature_1" | ||
| */ ] | ||
| "experiments": [ | ||
| "QuietBackgroundProcessesExperiment" |
| @@ -1,5 +1,5 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" xmlns:genTemplate="http://schemas.microsoft.com/appx/developer/templatestudio" xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6" IgnorableNamespaces="uap uap3 rescap genTemplate desktop6"> | |||
| <Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" xmlns:genTemplate="http://schemas.microsoft.com/appx/developer/templatestudio" xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6" IgnorableNamespaces="uap uap3 uap5 rescap genTemplate desktop6"> | |||
There was a problem hiding this comment.
Check that you're not changing the line endings here to LF.
|
|
||
| if (!_validOsVersion) | ||
| { | ||
| TimeLeft = "This feature requires OS version 10.0.26024.0+"; |
| // Copyright (c) Microsoft Corporation and Contributors | ||
| // Licensed under the MIT license. |
There was a problem hiding this comment.
Headers changed, if you merged main this should helpfully cause an error now. C++ files won't cause an error, but those will need to be addressed as well.
| <UseWinUI>true</UseWinUI> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <None Remove="Views\QuietBackgroundProcessesPage.xaml" /> |
There was a problem hiding this comment.
The QuiteBackgroundProcesses stuff should go in its own tools/QuietBackgroundProcesses project. All code should be written as if it wasn't an experimental feature, then the experimental feature checks just wrap it to enable/disable it. That way when it's not experimental anymore, we just remove the checks and the rest of the code stays exactly the same.
|
|
||
| namespace DevHome.QuietBackgroundProcesses | ||
| { | ||
| [default_interface] runtimeclass QuietBackgroundProcessesManager |
There was a problem hiding this comment.
Since the namespace is already "QuietBackgroundProcesses", the class can just be "Manager" or "QBPManager" if you really want to differentiate it.
There was a problem hiding this comment.
I had that originally, then I noticed that all the APIs keep the full name.
e.g. Windows.ApplicationModel.AppService has AppServiceConnection class
I think this is done so that all the using statements don't bring in multiple classes called something generic like "Manager" which then conflict.
personally i agree with your approach though.
| <description>An out-of-proc server for the QuietBackgroundProcesses feature.</description> | ||
| <dependencies> | ||
| <group targetFramework="net6.0-windows10.0.19041.0" /> | ||
| <group targetFramework=".NETCoreApp3.0" /> |
There was a problem hiding this comment.
Do you need all these target frameworks for downlevel?
| <file src="..\..\DevHome.QuietBackgroundProcesses.ElevatedServer\x64\Release\Merged\DevHome.QuietBackgroundProcesses.winmd" target="lib\uap10.0\DevHome.DevHome.QuietBackgroundProcesses.winmd" /> | ||
| <file src="..\..\DevHome.QuietBackgroundProcesses.ElevatedServer\x64\Release\Merged\DevHome.QuietBackgroundProcesses.winmd" target="lib\net46\DevHome.DevHome.QuietBackgroundProcesses.winmd" /> | ||
| <!-- Runtime --> | ||
| <file src="..\..\..\..\src\bin\x64\Release\net8.0-windows10.0.22000.0\DevHome.QuietBackgroundProcesses.ElevatedServer.exe" target="runtimes\win10-x64\native\DevHome.QuietBackgroundProcesses.ElevatedServer.exe" /> |
There was a problem hiding this comment.
| <file src="..\..\..\..\src\bin\x64\Release\net8.0-windows10.0.22000.0\DevHome.QuietBackgroundProcesses.ElevatedServer.exe" target="runtimes\win10-x64\native\DevHome.QuietBackgroundProcesses.ElevatedServer.exe" /> | |
| <file src="..\..\..\..\src\bin\x64\Release\net8.0-windows10.0.22000.0\DevHome.QuietBackgroundProcesses.ElevatedServer.exe" target="runtimes\win-x64\native\DevHome.QuietBackgroundProcesses.ElevatedServer.exe" /> | |
There was a problem hiding this comment.
Note that this reflects the change done for .NET 8 RID breaking change.
| @@ -0,0 +1,33 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <!-- | |||
There was a problem hiding this comment.
I think you can drop this file.
| <WholeProgramOptimization>true</WholeProgramOptimization> | ||
| <LinkIncremental>false</LinkIncremental> | ||
| </PropertyGroup> | ||
| <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
There was a problem hiding this comment.
We should set DesktopCompatible to true unconditional on what configuration / platform that it is being built for given we want it for all configurations.
| RETURN_HR_IF(E_UNEXPECTED, wil::compare_string_ordinal(WindowsGetStringRawBuffer(name, nullptr), L"DevHome.QuietBackgroundProcesses.QuietBackgroundProcessesManager", true) != 0); | ||
|
|
||
| auto manager = winrt::make<winrt::DevHome::QuietBackgroundProcesses::factory_implementation::QuietBackgroundProcessesManager>(); | ||
| manager.as<winrt::Windows::Foundation::IActivationFactory>(); |
There was a problem hiding this comment.
Doesn't as here return another ComPtr or no? Is this line needed?
| <file src="..\..\DevHome.QuietBackgroundProcesses.ElevatedServer\x64\Release\Merged\DevHome.QuietBackgroundProcesses.winmd" target="lib\uap10.0\DevHome.DevHome.QuietBackgroundProcesses.winmd" /> | ||
| <file src="..\..\DevHome.QuietBackgroundProcesses.ElevatedServer\x64\Release\Merged\DevHome.QuietBackgroundProcesses.winmd" target="lib\net46\DevHome.DevHome.QuietBackgroundProcesses.winmd" /> | ||
| <!-- Runtime --> | ||
| <file src="..\..\..\..\src\bin\x64\Release\net8.0-windows10.0.22000.0\DevHome.QuietBackgroundProcesses.ElevatedServer.exe" target="runtimes\win10-x64\native\DevHome.QuietBackgroundProcesses.ElevatedServer.exe" /> |
| } | ||
|
|
||
| //int _cdecl wmain(int argc, __in_ecount(argc) PWSTR wargv[]) | ||
| int CALLBACK wWinMain(_In_ HINSTANCE, _In_ HINSTANCE, _In_ LPWSTR wargv, _In_ int) |
There was a problem hiding this comment.
Just another question, is the C++ used in this PR needed? Could this have been done via C# instead?
| _zero = new TimeSpan(0, 0, 0); | ||
|
|
||
| var osVersion = Environment.OSVersion; | ||
| _validOsVersion = osVersion.Version.Build >= 26024; |
There was a problem hiding this comment.
Is comparing against the build number the only way to tell if this feature is on the computer?
|
|
||
| var osVersion = Environment.OSVersion; | ||
| _validOsVersion = osVersion.Version.Build >= 26024; | ||
| _validOsVersion = true; |
There was a problem hiding this comment.
Why do you set _validOsVersion to true here, when you have it set on line 29?
|
|
||
| if (!_validOsVersion) | ||
| { | ||
| TimeLeft = "This feature requires OS version 10.0.26024.0+"; |
There was a problem hiding this comment.
Why is it called TimeLeft if the string does not mention anything about time?
| if (!_validOsVersion) | ||
| { | ||
| TimeLeft = "This feature requires OS version 10.0.26024.0+"; | ||
| return; |
There was a problem hiding this comment.
Returning early is not ideal. Users of this constructor might think that QuietObjectViewModel is in a correct state even if the os version isn't correct. I recommend moving the OS version to methods that determine if QuietMode is supported.
| { | ||
| if (!_isElevated) | ||
| { | ||
| TimeLeft = "This feature requires running as admin"; |
There was a problem hiding this comment.
Is TimeLeft an error string?
| { | ||
| _isToggleOn = true; | ||
| var timeLeftInSeconds = GetTimeRemaining(); | ||
| StartCountdownTimer(timeLeftInSeconds); |
There was a problem hiding this comment.
is StartCountdownTimer synchronous? Won't this halt execution until the timer is done?
| private DispatcherTimer _dispatcherTimer; | ||
| private TimeSpan _secondsLeft; | ||
|
|
||
| private void StartCountdownTimer(long timeLeftInSeconds) |
There was a problem hiding this comment.
Consider using TimeSpan to durations instead of long/int
|
|
||
| <!-- Toggle switch --> | ||
| <StackPanel Orientation="Horizontal"> | ||
| <TextBlock Text="{x:Bind ViewModel.TimeLeft, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="16" Foreground="LightBlue" Margin="{StaticResource MediumLeftRightMargin}" Grid.Column="1" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" /> |
There was a problem hiding this comment.
Why does the TextBox use Grid.Column? Shouldn't that go into the StackPanel on line 29?
| <!-- Toggle switch --> | ||
| <StackPanel Orientation="Horizontal"> | ||
| <TextBlock Text="{x:Bind ViewModel.TimeLeft, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="16" Foreground="LightBlue" Margin="{StaticResource MediumLeftRightMargin}" Grid.Column="1" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" /> | ||
| <StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> |
There was a problem hiding this comment.
IF the only thing inside this StackPanel is a ToggleSwitch the StackPanel can be removed.
| /// </summary> | ||
| public sealed partial class QuietBackgroundProcessesPage : ToolPage | ||
| { | ||
| public override string ShortName => "Quiet Background Processes"; |
There was a problem hiding this comment.
Does this string need to be localized?
| void TimerThread() | ||
| { | ||
| // Pause until timer expired or cancelled | ||
| while (true) |
There was a problem hiding this comment.
is it possible to convert this to a do/while? Looks like you want some code to execute before the exit condition.
|
Closed in favor of #2322 (@jsidewhite please change if this is incorrect) |

Adding the "Enable 'Quiet Background Processes'" experimental feature to Dev Home. It's a toggle that is enabled similarly to Focus Assist mode, that expires after a period of time. When you enable it/toggle it on via the UI, Dev Home will call into the OS to enable quieting down background services (e.g. Search Indexer).
Summary of the pull request
References and relevant issues
Detailed description of the pull request / Additional comments
Validation steps performed
PR checklist