Skip to content
This repository was archived by the owner on Jun 5, 2025. It is now read-only.

Experimental Feature: Quiet Background Processes UI and WinRT server#2202

Closed
jsidewhite wants to merge 1 commit intomainfrom
user/jwhites/feature_quietbackgroundprocesses_devhome
Closed

Experimental Feature: Quiet Background Processes UI and WinRT server#2202
jsidewhite wants to merge 1 commit intomainfrom
user/jwhites/feature_quietbackgroundprocesses_devhome

Conversation

@jsidewhite
Copy link
Member

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

Summary of the pull request

References and relevant issues

Detailed description of the pull request / Additional comments

Validation steps performed

PR checklist

  • Closes #xxx
  • Tests added/passed
  • Documentation updated

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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quick question, did a content writer right these descriptions?

_zero = new TimeSpan(0, 0, 0);

var osVersion = Environment.OSVersion;
_validOsVersion = osVersion.Version.Build >= 26024;
Copy link
Contributor

@bbonaby bbonaby Feb 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using [ObservableProperty takes a bit of extra work at first, but the payoff is less code in code-behind.

</controls:SettingsCard>

<!-- Hyperlinks -->
<!--
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

// Copyright (c) Microsoft Corporation and Contributors
// Licensed under the MIT license.

namespace DevHome.QuietBackgroundProcesses
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jsidewhite
Copy link
Member Author

devhome ui

<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.4" />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't need to add this since we get it for free from DevHome.Common.

<ExcludeAssets>contentFiles</ExcludeAssets>
</PackageReference>
</ItemGroup>

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: put this blank line back.

"icon": "ea86"
}
/*,
,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: put this comma on line above.

"ExperimentalFeature_1"
*/ ]
"experiments": [
"QuietBackgroundProcessesExperiment"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: indentation

@@ -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">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check that you're not changing the line endings here to LF.


if (!_validOsVersion)
{
TimeLeft = "This feature requires OS version 10.0.26024.0+";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be localized?

Comment on lines +1 to +2
// Copyright (c) Microsoft Corporation and Contributors
// Licensed under the MIT license.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the namespace is already "QuietBackgroundProcesses", the class can just be "Manager" or "QBPManager" if you really want to differentiate it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had that originally, then I noticed that all the APIs keep the full name.

e.g. Windows.ApplicationModel.AppService has AppServiceConnection class

https://learn.microsoft.com/en-us/uwp/api/windows.applicationmodel.appservice.appserviceconnection?view=winrt-22621

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" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need all these target frameworks for downlevel?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for the winmds below.

<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" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<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" />

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this reflects the change done for .NET 8 RID breaking change.

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can drop this file.

<WholeProgramOptimization>true</WholeProgramOptimization>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>();
Copy link
Member

@manodasanW manodasanW Feb 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need ARM64?

}

//int _cdecl wmain(int argc, __in_ecount(argc) PWSTR wargv[])
int CALLBACK wWinMain(_In_ HINSTANCE, _In_ HINSTANCE, _In_ LPWSTR wargv, _In_ int)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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+";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is TimeLeft an error string?

{
_isToggleOn = true;
var timeLeftInSeconds = GetTimeRemaining();
StartCountdownTimer(timeLeftInSeconds);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is StartCountdownTimer synchronous? Won't this halt execution until the timer is done?

private DispatcherTimer _dispatcherTimer;
private TimeSpan _secondsLeft;

private void StartCountdownTimer(long timeLeftInSeconds)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this string need to be localized?

void TimerThread()
{
// Pause until timer expired or cancelled
while (true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it possible to convert this to a do/while? Looks like you want some code to execute before the exit condition.

@krschau
Copy link
Collaborator

krschau commented Feb 28, 2024

Closed in favor of #2322 (@jsidewhite please change if this is incorrect)

@krschau krschau closed this Feb 28, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants