Merge pull request #139 from spaceisfun/dontdisposenull

Fixes Bug 32803715: [Watson Failure] caused by CLR_EXCEPTION_System.NullReferenceException_80004003_Microsoft.FactoryOrchestrator.Service.dll!Microsoft.FactoryOrchestrator.Service.FOService.Dispose

Fixes backwards check for DisableContainerSupport

Fixes #113 - ResetService is buggy

Fixes #135 - Support /etc/FactoryOrchestrator/appsettings.json

Fixes #111 - WDP doesn't work on Desktop

Related to #140 - Implements the workaround, but will keep the issue open until an official .NET fix is made
This commit is contained in:
Jake Friedman 2021-04-27 20:06:26 -07:00 коммит произвёл GitHub
Родитель 433fffab1e 51c113eb72
Коммит 6db51c26e2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
20 изменённых файлов: 192 добавлений и 69 удалений

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

@ -8,7 +8,7 @@
description="Factory Orchestrator Service"
displayName="Factory Orchestrator Service"
errorControl="normal"
imagePath="%systemroot%\system32\manufacturing\FactoryOrchestrator\Microsoft.FactoryOrchestrator.Service.exe action:run"
imagePath="%systemroot%\system32\manufacturing\FactoryOrchestrator\Microsoft.FactoryOrchestrator.Service.exe -IsService"
name="Microsoft.FactoryOrchestrator.Service"
objectName="LocalSystem"
start="auto"

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

@ -0,0 +1,10 @@
#### [Microsoft.FactoryOrchestrator.Client](./Microsoft-FactoryOrchestrator-Client.md 'Microsoft.FactoryOrchestrator.Client')
### [Microsoft.FactoryOrchestrator.Client](./Microsoft-FactoryOrchestrator-Client.md 'Microsoft.FactoryOrchestrator.Client').[FactoryOrchestratorClient](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient.md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient')
## FactoryOrchestratorClient.GetWdpHttpPort() Method
Asynchronously Gets the Windows Device Portal HTTP port. Does not ensure WDP is running or supports HTTP.
```csharp
public System.Threading.Tasks.Task<int> GetWdpHttpPort();
```
#### Returns
[System.Threading.Tasks.Task&lt;](https://docs.microsoft.com/en-us/dotnet/api/System.Threading.Tasks.Task-1 'System.Threading.Tasks.Task')[System.Int32](https://docs.microsoft.com/en-us/dotnet/api/System.Int32 'System.Int32')[&gt;](https://docs.microsoft.com/en-us/dotnet/api/System.Threading.Tasks.Task-1 'System.Threading.Tasks.Task')
The HTTP port.

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

@ -12,7 +12,7 @@ If true, are logs not deleted.
<a name='Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-ResetService(bool_bool)-factoryReset'></a>
`factoryReset` [System.Boolean](https://docs.microsoft.com/en-us/dotnet/api/System.Boolean 'System.Boolean')
If true, the service is restarted as if it is first boot.
If true, the service is restarted as if it is first boot. NOTE: Network communication is not disabled, connected clients may encounter issues and the 'EnableNetworkAccess' setting will be ignored!
#### Returns
[System.Threading.Tasks.Task](https://docs.microsoft.com/en-us/dotnet/api/System.Threading.Tasks.Task 'System.Threading.Tasks.Task')

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

@ -62,6 +62,7 @@ Inheritance [System.Object](https://docs.microsoft.com/en-us/dotnet/api/System.O
- [GetServiceVersionString()](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetServiceVersionString().md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.GetServiceVersionString()')
- [GetTaskListGuids()](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetTaskListGuids().md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.GetTaskListGuids()')
- [GetTaskListSummaries()](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetTaskListSummaries().md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.GetTaskListSummaries()')
- [GetWdpHttpPort()](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetWdpHttpPort().md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.GetWdpHttpPort()')
- [InstallApp(string, System.Collections.Generic.List&lt;string&gt;, string)](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-InstallApp(string_System-Collections-Generic-List-string-_string).md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.InstallApp(string, System.Collections.Generic.List&lt;string&gt;, string)')
- [IsContainerRunning()](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-IsContainerRunning().md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.IsContainerRunning()')
- [IsExecutingBootTasks()](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-IsExecutingBootTasks().md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.IsExecutingBootTasks()')

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

@ -0,0 +1,10 @@
#### [Microsoft.FactoryOrchestrator.Core](./Microsoft-FactoryOrchestrator-Core.md 'Microsoft.FactoryOrchestrator.Core')
### [Microsoft.FactoryOrchestrator.Core](./Microsoft-FactoryOrchestrator-Core.md 'Microsoft.FactoryOrchestrator.Core').[IFactoryOrchestratorService](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService.md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService')
## IFactoryOrchestratorService.GetWdpHttpPort() Method
Gets the Windows Device Portal HTTP port. Does not ensure WDP is running or supports HTTP.
```csharp
int GetWdpHttpPort();
```
#### Returns
[System.Int32](https://docs.microsoft.com/en-us/dotnet/api/System.Int32 'System.Int32')
The HTTP port.

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

@ -12,5 +12,5 @@ If true, are logs not deleted.
<a name='Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-ResetService(bool_bool)-factoryReset'></a>
`factoryReset` [System.Boolean](https://docs.microsoft.com/en-us/dotnet/api/System.Boolean 'System.Boolean')
If true, the service is restarted as if it is first boot.
If true, the service is restarted as if it is first boot. NOTE: Network communication is not disabled, connected clients may encounter issues and the 'EnableNetworkAccess' setting will be ignored!

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

@ -35,6 +35,7 @@ public interface IFactoryOrchestratorService
- [GetServiceVersionString()](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-GetServiceVersionString().md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.GetServiceVersionString()')
- [GetTaskListGuids()](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-GetTaskListGuids().md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.GetTaskListGuids()')
- [GetTaskListSummaries()](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-GetTaskListSummaries().md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.GetTaskListSummaries()')
- [GetWdpHttpPort()](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-GetWdpHttpPort().md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.GetWdpHttpPort()')
- [InstallApp(string, System.Collections.Generic.List&lt;string&gt;, string)](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-InstallApp(string_System-Collections-Generic-List-string-_string).md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.InstallApp(string, System.Collections.Generic.List&lt;string&gt;, string)')
- [IsContainerRunning()](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-IsContainerRunning().md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.IsContainerRunning()')
- [IsExecutingBootTasks()](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-IsExecutingBootTasks().md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.IsExecutingBootTasks()')

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

@ -1,10 +1,11 @@
# Factory Orchestrator service configuration using appsettings.json
The Factory Orchestrator service has many configurable settings that impact its startup behavior, enabled features, and more. This configuration is easily modified using an [appsettings.json file](https://docs.microsoft.com/en-us/dotnet/core/extensions/configuration-providers#json-configuration-provider).
The appsettings.json file is checked for in two locations:
The appsettings.json file is checked for in the following locations:
- The directory where the service executable (Microsoft.FactoryOrchestrator.Service) is located
- The [service log file directory](#factory-orchestrator-service-log-file) (`%ProgramData%\FactoryOrchestrator\` or `/var/log/FactoryOrchestrator/`)
- The [service log file directory](#factory-orchestrator-service-log-file): `%ProgramData%\FactoryOrchestrator\` (Windows) or `/var/log/FactoryOrchestrator/`(Linux)
- (Linux only) The `/etc/FactoryOrchestrator/` directory
The following table describes each setting and its usage:

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

@ -56,7 +56,7 @@ else
}
else
{
$null = New-Service -Name "Microsoft.FactoryOrchestrator" -BinaryPathName "$installdir\Microsoft.FactoryOrchestrator.Service.exe" -Description "Factory Orchestrator service version $Version$" -StartupType Manual
$null = New-Service -Name "Microsoft.FactoryOrchestrator" -BinaryPathName "$installdir\Microsoft.FactoryOrchestrator.Service.exe -IsService" -Description "Factory Orchestrator service version $Version$" -StartupType Manual
}
Write-Host "Factory Orchestrator service version $Version$ is installed to `"$installdir`" and configured as a Windows service!`n"

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

@ -173,7 +173,7 @@
<value>Could not connect to {0}.
Check that the IP address, Server Name and Certificate Hash is correct and that the Factory Orchestrator Service is running on the target IP.</value>
<comment>Message displayed to the user if connection to the target machine cannot be established.</comment>
<comment>Message displayed to the user if connection to the target machine cannot be established.</comment>
</data>
<data name="BadIpTitle" xml:space="preserve">
<value>Unable to connect to target IP</value>
@ -283,7 +283,7 @@ Check that the IP address, Server Name and Certificate Hash is correct and that
Manually exported FactoryOrchestratorXML files will not be deleted, but will need to be manually imported via "Load FactoryOrchestratorXML file".
If "Factory Reset" is chosen, the service is restarted as if it is first boot. First boot and every boot tasks will re-run. Initial TaskLists will be loaded. "Factory Reset" will temporarily interrupt communication with clients, including this app.</value>
If "Factory Reset" is chosen, the service is restarted as if it is first boot. First boot and every boot tasks will re-run. Initial TaskLists will be loaded. NOTE: Network communication is not disabled, connected clients may encounter issues and the 'EnableNetworkAccess' setting will be ignored!</value>
</data>
<data name="DeleteButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Delete</value>
@ -720,7 +720,7 @@ On retry</value>
<value>Launch Windows Device Portal</value>
</data>
<data name="WDPFailedContent" xml:space="preserve">
<value>Make sure Windows Device Portal is running and try again.</value>
<value>Make sure Windows Device Portal is running and supports HTTP with no authentication, then try again.</value>
</data>
<data name="WDPFailedTitle" xml:space="preserve">
<value>Failed to launch Windows Device Portal</value>
@ -770,10 +770,10 @@ On retry</value>
</data>
<data name="CertHash.Text" xml:space="preserve">
<value>Certificate Hash:</value>
<comment>Hash value of the Certificate of the target machine.</comment>
<comment>Hash value of the Certificate of the target machine.</comment>
</data>
<data name="ServerName.Text" xml:space="preserve">
<value>Server Identity:</value>
<comment>Distinguished Name of the target machine.</comment>
<comment>Distinguished Name of the target machine.</comment>
</data>
</root>

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

@ -49,7 +49,7 @@ namespace Microsoft.FactoryOrchestrator.UWP
if (await IsWindowsDevicePortalRunning())
{
string ipAddress = Client.IsLocalHost ? "localhost" : $"{Client.IpAddress.ToString()}";
string url = "http://" + ipAddress + ":80";
string url = "http://" + ipAddress + ":" + await Client.GetWdpHttpPort();
Uri myUri = new Uri(url);
wdp.Navigate(myUri);
}

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

@ -157,7 +157,7 @@ namespace Microsoft.FactoryOrchestrator.Client
try
{
await WDPHelpers.InstallAppWithWDP(appFilename, dependentPackages, certificateFile, IpAddress.ToString());
await WDPHelpers.InstallAppWithWDP(appFilename, dependentPackages, certificateFile, IpAddress.ToString(), await GetWdpHttpPort());
}
catch (Exception ex)
{

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

@ -6,8 +6,8 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
namespace Microsoft.FactoryOrchestrator.Core
{
/// <summary>
@ -193,7 +193,7 @@ namespace Microsoft.FactoryOrchestrator.Core
/// Stops all running Tasks and deletes all TaskLists.
/// </summary>
/// <param name="preserveLogs">If true, are logs not deleted.</param>
/// <param name="factoryReset">If true, the service is restarted as if it is first boot.</param>
/// <param name="factoryReset">If true, the service is restarted as if it is first boot. NOTE: Network communication is not disabled, connected clients may encounter issues and the 'EnableNetworkAccess' setting will be ignored! </param>
void ResetService(bool preserveLogs = false, bool factoryReset = false);
/// <summary>
/// Gets all Service events.
@ -287,6 +287,11 @@ namespace Microsoft.FactoryOrchestrator.Core
/// </summary>
/// <returns><c>true</c> if the service allows connections over the local network.</returns>
bool IsNetworkAccessEnabled();
/// <summary>
/// Gets the Windows Device Portal HTTP port. Does not ensure WDP is running or supports HTTP.
/// </summary>
/// <returns>The HTTP port.</returns>
int GetWdpHttpPort();
// TaskList APIs
/// <summary>
@ -371,14 +376,14 @@ namespace Microsoft.FactoryOrchestrator.Core
/// </summary>
/// <param name="guid">The Task GUID.</param>
/// <returns></returns>
TaskBase QueryTask(Guid guid);
TaskBase QueryTask(Guid guid);
/// <summary>
/// Gets the AUMIDs of all installed apps on the OS. Requires Windows Device Portal.
/// </summary>
/// <returns>The list of app AUMIDs.</returns>
List<string> GetInstalledApps();
List<string> GetInstalledApps();
/// <summary>
/// Gets all installed apps on the OS. Requires Windows Device Portal.
/// </summary>

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

@ -26,6 +26,7 @@
<EmbeddedResource Include="FactoryOrchestratorXML.xsd">
<SubType>Designer</SubType>
</EmbeddedResource>
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Private.Uri" Version="4.3.2" />
@ -63,7 +64,7 @@
</Target>
<Target Name="FixAndCopyMd" AfterTargets="Build">
<ItemGroup>
<FilesToMove Include="$(DefaultDocumentationFolder)/*.md"/>
<FilesToMove Include="$(DefaultDocumentationFolder)/*.md" />
</ItemGroup>
<Exec Command="$(PowerShellExeName) $(ProjectDir)../../build/FixupAPIMarkdown.ps1 -DefaultDocumentationFolder $(DefaultDocumentationFolder)" />
<Move SourceFiles="@(FilesToMove)" DestinationFolder="../../docs/docs/CoreLibrary" />

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

@ -358,7 +358,7 @@
<value>Error: Failed to launch AUMID: {0}</value>
</data>
<data name="WDPAppLaunchFailed2" xml:space="preserve">
<value>Error: Device Portal is required for app launch and may not be running on the system.</value>
<value>Error: Device Portal is required for app launch and may not be running on the system or may not support HTTP with no authentication.</value>
</data>
<data name="WDPAppLaunchFailed3" xml:space="preserve">
<value>Error: If it is running, the AUMID may be incorrect.</value>
@ -373,7 +373,7 @@
<value>Windows Device Portal failed with HTTP error</value>
</data>
<data name="WDPNotRunningError" xml:space="preserve">
<value>Windows Device Portal must be running to call GetInstalledApps!</value>
<value>Windows Device Portal may not be running or may not support HTTP with no authentication!</value>
</data>
<data name="WindowsOnlyError" xml:space="preserve">
<value>{0} is only supported on Windows!</value>

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

@ -11,6 +11,7 @@ using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Win32;
namespace Microsoft.FactoryOrchestrator.Core
{
@ -79,6 +80,38 @@ namespace Microsoft.FactoryOrchestrator.Core
/// </summary>
public static readonly HttpClient WdpHttpClient = new HttpClient();
/// <summary>
/// Gets the Windows Device Portal HTTP port.
/// </summary>
public static int GetWdpHttpPort()
{
using (var osdata = Registry.LocalMachine.OpenSubKey(@"OSDATA\SOFTWARE\Microsoft\Windows\CurrentVersion\WebManagement\Service", false))
{
if (osdata != null)
{
var osdataPort = osdata.GetValue("HttpPort");
if (osdataPort != null)
{
return (int)osdataPort;
}
}
}
using (var sft = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\WebManagement\Service", false))
{
if (sft != null)
{
var port = sft.GetValue("HttpPort");
if (port != null)
{
return (int)port;
}
}
}
return 80;
}
private static HttpMultipartFileContent CreateAppInstallContent(string appFilePath, List<string> dependentAppsFilePaths, string certFilePath)
{
var content = new HttpMultipartFileContent();
@ -101,17 +134,19 @@ namespace Microsoft.FactoryOrchestrator.Core
/// Builds the application installation Uri and generates a unique boundary string for the multipart form data.
/// </summary>
/// <param name="packageName">The name of the application package.</param>
/// <param name="ipAddress">The ip address of the device to install the app on</param>
/// <param name="ipAddress">The ip address of the device to install the app on</param>
/// <param name="port">The port for WDP on the target device.</param>
/// <param name="uri">The endpoint for the install request.</param>
/// <param name="boundaryString">Unique string used to separate the parts of the multipart form data.</param>
private static void CreateAppInstallEndpointAndBoundaryString(
string packageName,
string ipAddress,
int port,
out Uri uri,
out string boundaryString)
{
uri = BuildEndpoint(
new Uri($"http://{ipAddress}"),
new Uri($"http://{ipAddress}:{port}"),
"api/app/packagemanager/package",
$"package={packageName}");
@ -135,12 +170,12 @@ namespace Microsoft.FactoryOrchestrator.Core
return new Uri(baseUri, relativePart);
}
private static async Task<ApplicationInstallStatus> GetInstallStatusAsync(string ipAddress = "localhost")
private static async Task<ApplicationInstallStatus> GetInstallStatusAsync(string ipAddress = "localhost", int port = 80)
{
ApplicationInstallStatus status = ApplicationInstallStatus.None;
Uri uri = BuildEndpoint(
new Uri($"http://{ipAddress}"),
new Uri($"http://{ipAddress}:{port}"),
"api/app/packagemanager/state");
using (HttpResponseMessage response = await WdpHttpClient.GetAsync(uri).ConfigureAwait(false))
@ -213,10 +248,11 @@ namespace Microsoft.FactoryOrchestrator.Core
/// <param name="appFilePath">The app package file path.</param>
/// <param name="dependentAppsFilePaths">The dependent app packages file paths.</param>
/// <param name="certFilePath">The certificate file path.</param>
/// <param name="ipAddress">The ip address of the device to install the app on.</param>
/// <param name="ipAddress">The ip address of the device to install the app on.</param>
/// <param name="port">The port for WDP on the target device.</param>
/// <exception cref="FileNotFoundException">
/// </exception>
public static async Task InstallAppWithWDP(string appFilePath, List<string> dependentAppsFilePaths, string certFilePath, string ipAddress = "localhost")
public static async Task InstallAppWithWDP(string appFilePath, List<string> dependentAppsFilePaths, string certFilePath, string ipAddress = "localhost", int port = 80)
{
ApplicationInstallStatus status = ApplicationInstallStatus.InProgress;
@ -244,7 +280,7 @@ namespace Microsoft.FactoryOrchestrator.Core
}
}
CreateAppInstallEndpointAndBoundaryString(Path.GetFileName(appFilePath), ipAddress, out var uri, out _);
CreateAppInstallEndpointAndBoundaryString(Path.GetFileName(appFilePath), ipAddress, port, out var uri, out _);
using (var content = CreateAppInstallContent(appFilePath, dependentAppsFilePaths, certFilePath))
{
await WdpHttpClient.PostAsync(uri, content);
@ -253,7 +289,7 @@ namespace Microsoft.FactoryOrchestrator.Core
while (status == ApplicationInstallStatus.InProgress)
{
await Task.Delay(500);
status = await GetInstallStatusAsync(ipAddress);
status = await GetInstallStatusAsync(ipAddress, port);
}
}
@ -262,17 +298,18 @@ namespace Microsoft.FactoryOrchestrator.Core
/// Closes a running app package application with Windows Device Portal.
/// </summary>
/// <param name="app">The app package to exit .</param>
/// <param name="ipAddress">The ip address of the device to exit the app on.</param>
/// <param name="ipAddress">The ip address of the device to exit the app on.</param>
/// <param name="port">The port for WDP on the target device.</param>
/// <exception cref="ArgumentException">
/// </exception>
public static async Task CloseAppWithWDP(string app, string ipAddress = "localhost")
public static async Task CloseAppWithWDP(string app, string ipAddress = "localhost", int port = 80)
{
if (string.IsNullOrWhiteSpace(app))
{
throw new ArgumentException(Resources.WDPError, nameof(app));
}
var uri = BuildEndpoint(new Uri($"http://{ipAddress}"),
var uri = BuildEndpoint(new Uri($"http://{ipAddress}:{port}"),
"api/taskmanager/app",
$"package={Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(app))}");
@ -283,11 +320,12 @@ namespace Microsoft.FactoryOrchestrator.Core
/// Gets the collection of applications installed on the device.
/// </summary>
/// <param name="ipAddress">The ip address of the device to query.</param>
/// <param name="port">The port for WDP on the target device.</param>
/// <returns>AppPackages object containing the list of installed application packages.</returns>
public static async Task<AppPackages> GetInstalledAppPackagesAsync(string ipAddress = "localhost")
public static async Task<AppPackages> GetInstalledAppPackagesAsync(string ipAddress = "localhost", int port = 80)
{
Uri uri = BuildEndpoint(
new Uri($"http://{ipAddress}"),
new Uri($"http://{ipAddress}:{port}"),
"api/app/packagemanager/packages");
var resp = await WdpHttpClient.GetAsync(uri).ConfigureAwait(false);

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

@ -11,7 +11,7 @@
<OutputPath>$(OutputRootPath)$(Configuration)/$(Platform)/$(TargetName)</OutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Security.Principal.Windows" Version="4.7.0" />
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../CoreLibrary/Microsoft.FactoryOrchestrator.Core.csproj" />

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

@ -414,8 +414,8 @@ namespace Microsoft.FactoryOrchestrator.Service
if (factoryReset)
{
// Pause a bit to allow the IPC call to return before we kill it off
Task.Run(() => { System.Threading.Thread.Sleep(500); FOService.Instance.Stop(); FOService.Instance.Start(true, new CancellationToken()); });
FOService.Instance.Stop(true);
FOService.Instance.Start(true, new CancellationToken());
}
}
catch (Exception e)
@ -802,12 +802,12 @@ namespace Microsoft.FactoryOrchestrator.Service
throw new FactoryOrchestratorException(string.Format(CultureInfo.CurrentCulture, Resources.WindowsOnlyError, "TerminateApp"));
}
var apps = WDPHelpers.GetInstalledAppPackagesAsync().Result;
var apps = WDPHelpers.GetInstalledAppPackagesAsync("localhost", WDPHelpers.GetWdpHttpPort()).Result;
var app = apps.Packages.Where(x => x.AppId.Equals(aumid, StringComparison.OrdinalIgnoreCase)).DefaultIfEmpty(null).FirstOrDefault();
if (app != null)
{
WDPHelpers.CloseAppWithWDP(app.FullName).Wait();
WDPHelpers.CloseAppWithWDP(app.FullName, "localhost", WDPHelpers.GetWdpHttpPort()).Wait();
}
FOService.Instance.ServiceLogger.LogDebug($"{Resources.Finish}: TerminateApp {aumid}");
@ -1014,7 +1014,7 @@ namespace Microsoft.FactoryOrchestrator.Service
}
}
WDPHelpers.InstallAppWithWDP(appPackagePath, dependentPackages, certificateFile).Wait();
WDPHelpers.InstallAppWithWDP(appPackagePath, dependentPackages, certificateFile, "localhost", WDPHelpers.GetWdpHttpPort()).Wait();
FOService.Instance.ServiceLogger.LogDebug($"{Resources.Finish}: InstallApp {appPackagePath}");
}
@ -1037,7 +1037,7 @@ namespace Microsoft.FactoryOrchestrator.Service
}
// Get installed packages on the system
var apps = WDPHelpers.GetInstalledAppPackagesAsync().Result;
var apps = WDPHelpers.GetInstalledAppPackagesAsync("localhost", WDPHelpers.GetWdpHttpPort()).Result;
List<string> aumids = apps.Packages.Select(x => x.AppId).ToList();
@ -1063,7 +1063,7 @@ namespace Microsoft.FactoryOrchestrator.Service
}
// Get installed packages on the system
var apps = WDPHelpers.GetInstalledAppPackagesAsync().Result;
var apps = WDPHelpers.GetInstalledAppPackagesAsync("localhost", WDPHelpers.GetWdpHttpPort()).Result;
FOService.Instance.ServiceLogger.LogDebug($"{Resources.Finish}: GetInstalledAppsDetailed");
return apps.Packages;
@ -1238,5 +1238,21 @@ namespace Microsoft.FactoryOrchestrator.Service
throw;
}
}
public int GetWdpHttpPort()
{
try
{
FOService.Instance.ServiceLogger.LogDebug($"{Resources.Start}: GetWdpHttpPort");
int ret = WDPHelpers.GetWdpHttpPort();
FOService.Instance.ServiceLogger.LogDebug($"{Resources.Finish}: GetWdpHttpPort");
return ret;
}
catch (Exception e)
{
FOService.Instance.LogServiceEvent(new ServiceEvent(ServiceEventType.ServiceError, null, e.AllExceptionsToString()));
throw;
}
}
}
}

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

@ -2,7 +2,7 @@
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
@ -16,7 +16,9 @@ using JKang.IpcServiceFramework.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Hosting.WindowsServices;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.EventLog;
using Microsoft.FactoryOrchestrator.Client;
using Microsoft.FactoryOrchestrator.Core;
using Microsoft.FactoryOrchestrator.Server;
@ -106,19 +108,43 @@ namespace Microsoft.FactoryOrchestrator.Service
}).Build();
public static void Main(string[] args)
{
Host.CreateDefaultBuilder(null).UseSystemd().UseWindowsService().ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
}).ConfigureLogging(builder =>
{
{
#if DEBUG
var _logLevel = LogLevel.Debug;
var _logLevel = LogLevel.Debug;
#else
var _logLevel = LogLevel.Information;
var _logLevel = LogLevel.Information;
#endif
builder.SetMinimumLevel(_logLevel).AddConsole().AddProvider(new LogFileProvider());
}).Build().Run();
var hostBuilder = Host.CreateDefaultBuilder(null).UseSystemd().ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
}).ConfigureLogging(builder =>
{
builder.SetMinimumLevel(_logLevel).AddConsole().AddProvider(new LogFileProvider());
});
bool isService = ((args != null) && (args.Length > 0));
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && isService)
{
hostBuilder.UseContentRoot(AppContext.BaseDirectory);
hostBuilder.ConfigureLogging((hostingContext, logging) =>
{
logging.AddEventLog();
logging.SetMinimumLevel(_logLevel);
})
.ConfigureServices((hostContext, services) =>
{
services.AddSingleton<IHostLifetime, WindowsServiceLifetime>();
services.Configure<EventLogSettings>(settings =>
{
if (string.IsNullOrEmpty(settings.SourceName))
{
settings.SourceName = hostContext.HostingEnvironment.ApplicationName;
}
});
});
}
hostBuilder.Build().Run();
}
}
@ -447,10 +473,13 @@ namespace Microsoft.FactoryOrchestrator.Service
return;
}
// Start IPC server on desired port. Only start after all boot tasks are complete.
_ipcHost = FOServiceExe.CreateIpcHost(IsNetworkAccessEnabled, NetworkPort, SSLCertificate);
_ipcCancellationToken = new System.Threading.CancellationTokenSource();
_ipcHost.RunAsync(_ipcCancellationToken.Token);
// Start IPC server on desired port. Only start if not a reset operation.
if (_ipcHost == null)
{
_ipcHost = FOServiceExe.CreateIpcHost(IsNetworkAccessEnabled, NetworkPort, SSLCertificate);
_ipcCancellationToken = new System.Threading.CancellationTokenSource();
_ipcHost.RunAsync(_ipcCancellationToken.Token);
}
if (IsNetworkAccessEnabled)
{
@ -531,10 +560,14 @@ namespace Microsoft.FactoryOrchestrator.Service
/// <summary>
/// Service stop.
/// </summary>
public void Stop()
{
// Disable inter process communication interfaces
_ipcCancellationToken?.Cancel();
public void Stop(bool isFactoryReset = false)
{
if (!isFactoryReset)
{
// Disable inter process communication interfaces if not a reset operation
_ipcCancellationToken?.Cancel();
}
_containerHeartbeatToken?.Cancel();
_containerClient = null;
ContainerGuid = Guid.Empty;
@ -719,13 +752,13 @@ namespace Microsoft.FactoryOrchestrator.Service
{
// Exit URDC if we launched it.
// There may be a preview app & official app installed, close them all
var rdApps = (await WDPHelpers.GetInstalledAppPackagesAsync()).Packages.Where(x => (x.FullName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase)) && (x.FullName.Contains("RemoteDesktop", StringComparison.OrdinalIgnoreCase)));
var rdApps = (await WDPHelpers.GetInstalledAppPackagesAsync("localhost", WDPHelpers.GetWdpHttpPort())).Packages.Where(x => (x.FullName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase)) && (x.FullName.Contains("RemoteDesktop", StringComparison.OrdinalIgnoreCase)));
foreach (var app in rdApps)
{
try
{
await WDPHelpers.CloseAppWithWDP(app.FullName);
await WDPHelpers.CloseAppWithWDP(app.FullName, "localhost", WDPHelpers.GetWdpHttpPort());
}
catch (Exception)
{
@ -1192,6 +1225,8 @@ namespace Microsoft.FactoryOrchestrator.Service
/// <returns></returns>
public void ExecuteServerBootTasks(CancellationToken cancellationToken)
{
IsExecutingBootTasks = true;
if (_isWindows)
{
// Open Registry Keys
@ -1266,7 +1301,6 @@ namespace Microsoft.FactoryOrchestrator.Service
LastEventIndex = 0;
LastEventTime = DateTime.MinValue;
LocalLoopbackApps = new List<string>();
IsExecutingBootTasks = true;
_openedFiles = new Dictionary<string, (Stream stream, System.Threading.Timer timer)>();
ContainerGuid = Guid.Empty;
@ -1686,6 +1720,12 @@ namespace Microsoft.FactoryOrchestrator.Service
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile(Path.Combine(FOServiceExe.ServiceExeLogFolder, "appsettings.json"), optional: true)
.AddJsonFile("appsettings.json", optional: true);
if (!_isWindows)
{
builder.AddJsonFile("/etc/FactoryOrchestrator/appsettings.json", optional:true);
}
Appsettings = builder.Build();
// Look for each setting in the registry (Windows only, OEM Customizations) or in the IConfiguration
@ -1804,7 +1844,7 @@ namespace Microsoft.FactoryOrchestrator.Service
{
try
{
IsContainerSupportEnabled = Convert.ToBoolean(GetAppSetting(_disableContainerValue) ?? new ArgumentNullException(), CultureInfo.InvariantCulture);
IsContainerSupportEnabled = !Convert.ToBoolean(GetAppSetting(_disableContainerValue) ?? new ArgumentNullException(), CultureInfo.InvariantCulture);
}
catch (Exception)
{
@ -1941,7 +1981,7 @@ namespace Microsoft.FactoryOrchestrator.Service
{
if (disposing)
{
_ipcHost.Dispose();
_ipcHost?.Dispose();
_ipcCancellationToken?.Dispose();
_containerHeartbeatToken?.Dispose();
_mutableKey?.Dispose();

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

@ -3,7 +3,7 @@
<!-- Assembly, App, Package version for all non-OSS files. Uses SemVer. -->
<PropertyGroup Label="Version">
<VersionPrefix>10.0.0</VersionPrefix>
<VersionPrefix>10.1.0</VersionPrefix>
</PropertyGroup>
<!-- Common packaging properties -->