[platform] refactoring 'update.xml' requests parameter setting (IJPL-159831)

In particular, the change removes service access from `UpdateChecker#<clinit>`.

GitOrigin-RevId: 962f01a45ecead1310fa8fe15659d276b6a7c7ba
This commit is contained in:
Roman Shevchenko
2024-09-18 16:17:26 +02:00
committed by intellij-monorepo-bot
parent 5509994a0e
commit e2e06928e6
7 changed files with 122 additions and 61 deletions

View File

@@ -16321,8 +16321,6 @@ e:com.intellij.openapi.updateSettings.impl.UpdateChannel$Licensing
- s:values():com.intellij.openapi.updateSettings.impl.UpdateChannel$Licensing[]
f:com.intellij.openapi.updateSettings.impl.UpdateChecker
- sf:INSTANCE:com.intellij.openapi.updateSettings.impl.UpdateChecker
- sf:MACHINE_ID_DISABLED_PROPERTY:java.lang.String
- sf:MACHINE_ID_PARAMETER:java.lang.String
- sf:NOTIFICATIONS:com.intellij.notification.NotificationGroup
- sf:checkAndPrepareToInstall(com.intellij.openapi.updateSettings.impl.PluginDownloader,com.intellij.ide.plugins.InstalledPluginsState,java.util.Map):V
- sf:checkAndPrepareToInstall(com.intellij.openapi.updateSettings.impl.PluginDownloader,com.intellij.ide.plugins.InstalledPluginsState,java.util.Map,com.intellij.openapi.util.BuildNumber):V
@@ -21507,6 +21505,7 @@ f:com.intellij.ui.LicensingFacade
- platformProductCode:java.lang.String
- productLicenses:java.util.Map
- restrictions:java.util.List
- subType:java.lang.String
- <init>():V
- s:fromJson(java.lang.String):com.intellij.ui.LicensingFacade
- getConfirmationStamp(java.lang.String):java.lang.String

View File

@@ -7,7 +7,6 @@ import com.intellij.ide.externalComponents.ExternalComponentSource
import com.intellij.ide.plugins.*
import com.intellij.ide.plugins.marketplace.MarketplaceRequests
import com.intellij.ide.util.PropertiesComponent
import com.intellij.internal.statistic.eventLog.fus.MachineIdManager
import com.intellij.notification.*
import com.intellij.openapi.actionSystem.PlatformCoreDataKeys
import com.intellij.openapi.application.*
@@ -23,11 +22,14 @@ import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.updateSettings.impl.UpdateChecker.MACHINE_ID_DISABLED_PROPERTY
import com.intellij.openapi.util.*
import com.intellij.openapi.util.ActionCallback
import com.intellij.openapi.util.BuildNumber
import com.intellij.openapi.util.JDOMUtil
import com.intellij.openapi.util.NlsContexts
import com.intellij.openapi.util.text.HtmlBuilder
import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame
import com.intellij.platform.ide.customization.ExternalProductResourceUrls
import com.intellij.util.Url
import com.intellij.util.concurrency.AppExecutorUtil
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
import com.intellij.util.concurrency.annotations.RequiresEdt
@@ -62,7 +64,6 @@ private const val DISABLED_UPDATE = "disabled_update.txt"
private const val DISABLED_PLUGIN_UPDATE = "plugin_disabled_updates.txt"
private const val PRODUCT_DATA_TTL_MIN = 5L
private var machineIdInitialized = false
private val shownNotifications = MultiMap<NotificationKind, Notification>()
@Service
@@ -96,10 +97,11 @@ private class UpdateCheckerHelper(private val coroutineScope: CoroutineScope) {
* See XML file by [ApplicationInfoEx.getUpdateUrls] for reference.
*/
object UpdateChecker {
const val MACHINE_ID_DISABLED_PROPERTY: String = "machine.id.disabled"
const val MACHINE_ID_PARAMETER: String = "mid"
internal const val MACHINE_ID_DISABLED_PROPERTY: String = "machine.id.disabled"
internal const val MACHINE_ID_PARAMETER: String = "mid"
private val productDataLock = ReentrantLock()
private var productDataUrl: Url? = null
private var productDataCache: SoftReference<Result<Product?>>? = null
private val ourUpdatedPlugins: MutableMap<PluginId, PluginDownloader> = HashMap()
@@ -109,19 +111,6 @@ object UpdateChecker {
*/
val excludedFromUpdateCheckPlugins: HashSet<String> = hashSetOf()
init {
UpdateRequestParameters.addParameter("build", ApplicationInfo.getInstance().build.asString())
UpdateRequestParameters.addParameter("uid", PermanentInstallationID.get())
UpdateRequestParameters.addParameter("os", SystemInfo.OS_NAME + ' ' + SystemInfo.OS_VERSION)
if (ExternalUpdateManager.ACTUAL != null) {
val name = if (ExternalUpdateManager.ACTUAL == ExternalUpdateManager.TOOLBOX) "Toolbox" else ExternalUpdateManager.ACTUAL.toolName
UpdateRequestParameters.addParameter("manager", name)
}
if (ApplicationInfoEx.getInstanceEx().isEAP) {
UpdateRequestParameters.addParameter("eap", "")
}
}
@JvmStatic
fun getNotificationGroup(): NotificationGroup =
NotificationGroupManager.getInstance().getNotificationGroup("IDE and Plugin Updates")
@@ -197,11 +186,12 @@ object UpdateChecker {
@JvmStatic
@Throws(IOException::class, JDOMException::class)
fun loadProductData(indicator: ProgressIndicator?): Product? =
productDataLock.withLock {
fun loadProductData(indicator: ProgressIndicator?): Product? {
val url = ExternalProductResourceUrls.getInstance().updateMetadataUrl ?: return null
return productDataLock.withLock {
val cached = productDataCache?.get()
if (cached != null) return@withLock cached.getOrThrow()
val url = ExternalProductResourceUrls.getInstance().updateMetadataUrl ?: return@withLock null
if (cached != null && url == productDataUrl) return@withLock cached.getOrThrow()
val result = runCatching {
LOG.debug { "loading ${url}" }
@@ -211,19 +201,21 @@ object UpdateChecker {
?.also {
if (it.disableMachineId) {
PropertiesComponent.getInstance().setValue(MACHINE_ID_DISABLED_PROPERTY, true)
UpdateRequestParameters.removeParameter(MACHINE_ID_PARAMETER)
}
}
}
productDataCache = SoftReference(result)
productDataUrl = url
AppExecutorUtil.getAppScheduledExecutorService().schedule(this::clearProductDataCache, PRODUCT_DATA_TTL_MIN, TimeUnit.MINUTES)
return@withLock result.getOrThrow()
result.getOrThrow()
}
}
private fun clearProductDataCache() {
if (productDataLock.tryLock(1, TimeUnit.MILLISECONDS)) { // a longer time means loading now, no much sense in clearing
productDataCache = null
productDataUrl = null
productDataLock.unlock()
}
}
@@ -615,14 +607,6 @@ private fun doUpdateAndShowResult(
indicator: ProgressIndicator? = null,
callback: ActionCallback? = null,
): (() -> Unit)? {
if (!PropertiesComponent.getInstance().getBoolean(MACHINE_ID_DISABLED_PROPERTY, false) && !machineIdInitialized) {
machineIdInitialized = true
val machineId = MachineIdManager.getAnonymizedMachineId("JetBrainsUpdates", "")
if (machineId != null) {
UpdateRequestParameters.addParameter(UpdateChecker.MACHINE_ID_PARAMETER, machineId)
}
}
val updateSettings = customSettings ?: UpdateSettings.getInstance()
val platformUpdates = UpdateChecker.getPlatformUpdates(updateSettings, indicator)

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.updateSettings.impl;
import com.intellij.ide.AppLifecycleListener;
@@ -29,6 +29,7 @@ import com.intellij.util.SystemProperties;
import com.intellij.util.Url;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.text.DateFormatUtil;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.VisibleForTesting;
@@ -44,7 +45,8 @@ import java.util.concurrent.TimeUnit;
import static java.lang.Math.max;
final class UpdateCheckerService {
@ApiStatus.Internal
class UpdateCheckerService {
public static UpdateCheckerService getInstance() {
return ApplicationManager.getApplication().getService(UpdateCheckerService.class);
}
@@ -126,7 +128,7 @@ final class UpdateCheckerService {
}
}
private void scheduleFirstCheck(UpdateSettings settings) {
void scheduleFirstCheck(UpdateSettings settings) {
BuildNumber currentBuild = ApplicationInfo.getInstance().getBuild();
BuildNumber lastBuildChecked = BuildNumber.fromString(settings.getLastBuildChecked());
long timeSinceLastCheck = max(System.currentTimeMillis() - settings.getLastTimeChecked(), 0);

View File

@@ -1,33 +1,60 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.updateSettings.impl;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.internal.statistic.eventLog.fus.MachineIdManager;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.PermanentInstallationID;
import com.intellij.openapi.application.ex.ApplicationInfoEx;
import com.intellij.openapi.util.NullableLazyValue;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.ui.LicensingFacade;
import com.intellij.util.Url;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedHashMap;
import static com.intellij.openapi.util.NullableLazyValue.lazyNullable;
@ApiStatus.Internal
public final class UpdateRequestParameters {
private static final Map<String, String> ourParameters = new HashMap<>();
private static final NullableLazyValue<String> ourMachineId =
lazyNullable(() -> MachineIdManager.INSTANCE.getAnonymizedMachineId("JetBrainsUpdates", ""));
public static void addParameter(@NotNull String name, @NotNull String value) {
synchronized (ourParameters) {
ourParameters.put(name, value);
}
}
public static void removeParameter(@NotNull String name) {
synchronized (ourParameters) {
ourParameters.remove(name);
}
}
@ApiStatus.Internal
public static @NotNull Url amendUpdateRequest(@NotNull Url url) {
synchronized (ourParameters) {
return url.addParameters(ourParameters);
var parameters = new LinkedHashMap<String, String>();
parameters.put("build", ApplicationInfo.getInstance().getBuild().asString());
parameters.put("os", SystemInfo.OS_NAME + ' ' + SystemInfo.OS_VERSION);
if (ApplicationInfoEx.getInstanceEx().isEAP()) {
parameters.put("eap", "");
}
parameters.put("uid", PermanentInstallationID.get());
if (!PropertiesComponent.getInstance().getBoolean(UpdateChecker.MACHINE_ID_DISABLED_PROPERTY, false)) {
var machineId = ourMachineId.getValue();
if (machineId != null) {
parameters.put("mid", machineId);
}
}
if (ExternalUpdateManager.ACTUAL != null) {
var name = ExternalUpdateManager.ACTUAL == ExternalUpdateManager.TOOLBOX ? "Toolbox" : ExternalUpdateManager.ACTUAL.toolName;
parameters.put("manager", name);
}
var facade = LicensingFacade.getInstance();
if (facade != null) {
var subType = facade.subType;
if (subType != null) {
parameters.put("license", subType);
}
}
return url.addParameters(parameters);
}
}

View File

@@ -64,8 +64,9 @@ abstract class BaseJetBrainsExternalProductResourceUrls : ExternalProductResourc
get() = false
override val updateMetadataUrl: Url
get() = System.getProperty("idea.updates.url")?.let { Urls.newFromEncoded(it) }
?: UpdateRequestParameters.amendUpdateRequest(Urls.newFromEncoded("https://www.jetbrains.com/updates/updates.xml"))
get() = System.getProperty("idea.updates.url", "https://www.jetbrains.com/updates/updates.xml")
.let { Urls.newFromEncoded(it) }
.let { UpdateRequestParameters.amendUpdateRequest(it) }
final override fun computePatchUrl(from: BuildNumber, to: BuildNumber): Url =
computeCustomPatchDownloadUrl(from, to)

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.ui;
import com.google.gson.Gson;
@@ -26,7 +26,7 @@ public final class LicensingFacade {
public Map<String, String> confirmationStamps;
public Map<String, ProductLicenseData> productLicenses;
public String metadata;
public boolean ai_enabled;
@SuppressWarnings("StaticNonFinalField")
public static volatile boolean isUnusedSignalled;
/**
@@ -34,6 +34,7 @@ public final class LicensingFacade {
*/
@Deprecated
public static volatile LicensingFacade INSTANCE;
public String subType;
public static @Nullable LicensingFacade getInstance() {
return INSTANCE;
@@ -117,6 +118,12 @@ public final class LicensingFacade {
return result != null? result.get(productCode) : null;
}
@ApiStatus.Internal
public static void setInstance(@Nullable LicensingFacade instance) {
INSTANCE = instance;
ApplicationManager.getApplication().getMessageBus().syncPublisher(LicenseStateListener.TOPIC).licenseStateChanged(instance);
}
private static @NotNull Gson createGson() {
return new GsonBuilder().setDateFormat("yyyyMMdd").create();
}

View File

@@ -0,0 +1,41 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.testFramework.junit5;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import java.net.InetSocketAddress;
@SuppressWarnings("HttpUrlsUsage")
public class SimpleHttpServer implements BeforeEachCallback, AfterEachCallback {
private static final String LOCALHOST = "127.0.0.1";
public HttpServer server;
public String url;
@Override
public void beforeEach(ExtensionContext context) throws Exception {
server = HttpServer.create();
server.bind(new InetSocketAddress(LOCALHOST, 0), 1);
server.start();
url = "http://%s:%s".formatted(LOCALHOST, server.getAddress().getPort());
}
@Override
public void afterEach(ExtensionContext context) throws Exception {
if (server != null) {
url = null;
server.stop(0);
server = null;
}
}
public @NotNull HttpContext createContext(@NotNull String path, @NotNull HttpHandler handler) {
return server.createContext(path, handler);
}
}