Android14 - Framework- Configuration的创建和更新

news2024/9/24 1:16:25

本文描述启动一个新进程ActivityFramworkConfiguration创建传导过程

首先我们知道所有Window容器继承于WindowContainerWindowContainer本身ConfigurationContainer子类于此同时WindowProcessController也是ConfigurationContainer子类ConfigurationContainer认为可以Window进程进行Configuration配置基本载体单位

我们启动一个Activity角度出发Configuration的传导过程

启动Activity过程调用ActivityTaskSupervisorrealStartActivityLocked方法

platform/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java

boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
	boolean andResume, boolean checkConfig) throws RemoteException {
    ...
    if (checkConfig) {
		// Deferring resume here because we're going to launch new activity shortly.
		// We don't want to perform a redundant launch of the same record while ensuring
		// configurations and trying to resume top activity of focused root task.
		mRootWindowContainer.ensureVisibilityAndConfig(r, r.getDisplayId(),
				false /* markFrozenIfConfigChanged */, true /* deferResume */);
	}
    ...
}

Activity启动场景checkConfigtrue

看ensureVisibilityAndConfig

platform/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

boolean ensureVisibilityAndConfig(ActivityRecord starting, int displayId,
		boolean markFrozenIfConfigChanged, boolean deferResume) {
	// First ensure visibility without updating the config just yet. We need this to know what
	// activities are affecting configuration now.
	// Passing null here for 'starting' param value, so that visibility of actual starting
	// activity will be properly updated.
	ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
			false /* preserveWindows */, false /* notifyClients */);

	if (displayId == INVALID_DISPLAY) {
		// The caller didn't provide a valid display id, skip updating config.
		return true;
	}

	// Force-update the orientation from the WindowManager, since we need the true configuration
	// to send to the client now.
	final DisplayContent displayContent = getDisplayContent(displayId);
	Configuration config = null;
	if (displayContent != null) {
		config = displayContent.updateOrientation(starting, true /* forceUpdate */);
	}
	// Visibilities may change so let the starting activity have a chance to report. Can't do it
	// when visibility is changed in each AppWindowToken because it may trigger wrong
	// configuration push because the visibility of some activities may not be updated yet.
	if (starting != null) {
		starting.reportDescendantOrientationChangeIfNeeded();
	}
	if (starting != null && markFrozenIfConfigChanged && config != null) {
		starting.frozenBeforeDestroy = true;
	}

	if (displayContent != null) {
		// Update the configuration of the activities on the display.
		return displayContent.updateDisplayOverrideConfigurationLocked(config, starting,
				deferResume, null /* result */);
	} else {
		return true;
	}
}

调用了DisplayContentupdateOrientation注意这里第二个参数forceUpdatetrue强制更新

platform/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

Configuration updateOrientation(WindowContainer<?> freezeDisplayWindow, boolean forceUpdate) {
	if (!mDisplayReady) {
		return null;
	}

	Configuration config = null;
	if (updateOrientation(forceUpdate)) {
		// If we changed the orientation but mOrientationChangeComplete is already true,
		// we used seamless rotation, and we don't need to freeze the screen.
		if (freezeDisplayWindow != null && !mWmService.mRoot.mOrientationChangeComplete) {
			final ActivityRecord activity = freezeDisplayWindow.asActivityRecord();
			if (activity != null && activity.mayFreezeScreenLocked()) {
				activity.startFreezingScreen();
			}
		}
		config = new Configuration();
		computeScreenConfiguration(config);
	}

	return config;
}

如果需要更新Orientation创建new Configuration()调用computeScreenConfiguration

platform/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

/**
 * Compute display configuration based on display properties and policy settings.
 * Do not call if mDisplayReady == false.
 */
void computeScreenConfiguration(Configuration config) {
	final DisplayInfo displayInfo = updateDisplayAndOrientation(config);
	final int dw = displayInfo.logicalWidth;
	final int dh = displayInfo.logicalHeight;
	mTmpRect.set(0, 0, dw, dh);
	config.windowConfiguration.setBounds(mTmpRect);
	config.windowConfiguration.setMaxBounds(mTmpRect);
	config.windowConfiguration.setWindowingMode(getWindowingMode());
	config.windowConfiguration.setDisplayWindowingMode(getWindowingMode());

	computeScreenAppConfiguration(config, dw, dh, displayInfo.rotation);

	config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
			| ((displayInfo.flags & Display.FLAG_ROUND) != 0
			? Configuration.SCREENLAYOUT_ROUND_YES
			: Configuration.SCREENLAYOUT_ROUND_NO);

	config.densityDpi = displayInfo.logicalDensityDpi;

	config.colorMode =
			((displayInfo.isHdr() && mWmService.hasHdrSupport())
					? Configuration.COLOR_MODE_HDR_YES
					: Configuration.COLOR_MODE_HDR_NO)
					| (displayInfo.isWideColorGamut() && mWmService.hasWideColorGamutSupport()
					? Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES
					: Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO);

	// Update the configuration based on available input devices, lid switch,
	// and platform configuration.
	config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
	config.keyboard = Configuration.KEYBOARD_NOKEYS;
	config.navigation = Configuration.NAVIGATION_NONAV;

	int keyboardPresence = 0;
	int navigationPresence = 0;
	final InputDevice[] devices = mWmService.mInputManager.getInputDevices();
	final int len = devices != null ? devices.length : 0;
	for (int i = 0; i < len; i++) {
		InputDevice device = devices[i];
		// Ignore virtual input device.
		if (device.isVirtual()) {
			continue;
		}

		// Check if input device can dispatch events to current display.
		if (!mWmService.mInputManager.canDispatchToDisplay(device.getId(), mDisplayId)) {
			continue;
		}

		final int sources = device.getSources();
		final int presenceFlag = device.isExternal()
				? WindowManagerPolicy.PRESENCE_EXTERNAL : WindowManagerPolicy.PRESENCE_INTERNAL;

		if (mWmService.mIsTouchDevice) {
			if ((sources & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN) {
				config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
			}
		} else {
			config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
		}

		if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
			config.navigation = Configuration.NAVIGATION_TRACKBALL;
			navigationPresence |= presenceFlag;
		} else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
				&& config.navigation == Configuration.NAVIGATION_NONAV) {
			config.navigation = Configuration.NAVIGATION_DPAD;
			navigationPresence |= presenceFlag;
		}

		if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
			config.keyboard = Configuration.KEYBOARD_QWERTY;
			keyboardPresence |= presenceFlag;
		}
	}

	if (config.navigation == Configuration.NAVIGATION_NONAV && mWmService.mHasPermanentDpad) {
		config.navigation = Configuration.NAVIGATION_DPAD;
		navigationPresence |= WindowManagerPolicy.PRESENCE_INTERNAL;
	}

	// Determine whether a hard keyboard is available and enabled.
	// TODO(multi-display): Should the hardware keyboard be tied to a display or to a device?
	boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
	if (hardKeyboardAvailable != mWmService.mHardKeyboardAvailable) {
		mWmService.mHardKeyboardAvailable = hardKeyboardAvailable;
		mWmService.mH.removeMessages(REPORT_HARD_KEYBOARD_STATUS_CHANGE);
		mWmService.mH.sendEmptyMessage(REPORT_HARD_KEYBOARD_STATUS_CHANGE);
	}

	mDisplayPolicy.updateConfigurationAndScreenSizeDependentBehaviors();

	// Let the policy update hidden states.
	config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
	config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
	config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
	mWmService.mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
}

computeScreenAppConfiguration用来更新屏幕尺寸密度、rotation

platform/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

/** Compute configuration related to application without changing current display. */
private void computeScreenAppConfiguration(Configuration outConfig, int dw, int dh,
		int rotation) {
	final DisplayPolicy.DecorInsets.Info info =
			mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh);
	// AppBounds at the root level should mirror the app screen size.
	outConfig.windowConfiguration.setAppBounds(info.mNonDecorFrame);
	outConfig.windowConfiguration.setRotation(rotation);
	outConfig.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;

	final float density = mDisplayMetrics.density;
	outConfig.screenWidthDp = (int) (info.mConfigFrame.width() / density + 0.5f);
	outConfig.screenHeightDp = (int) (info.mConfigFrame.height() / density + 0.5f);
	outConfig.compatScreenWidthDp = (int) (outConfig.screenWidthDp / mCompatibleScreenScale);
	outConfig.compatScreenHeightDp = (int) (outConfig.screenHeightDp / mCompatibleScreenScale);
	outConfig.screenLayout = computeScreenLayout(
			Configuration.resetScreenLayout(outConfig.screenLayout),
			outConfig.screenWidthDp, outConfig.screenHeightDp);

	final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
	outConfig.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dw, dh);
	outConfig.windowConfiguration.setDisplayRotation(rotation);
}

回到ensureVisibilityAndConfig 获取Configuration调用displayContent.updateDisplayOverrideConfigurationLocked

platform/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

/**
 * Updates override configuration specific for the selected display. If no config is provided,
 * new one will be computed in WM based on current display info.
 */
boolean updateDisplayOverrideConfigurationLocked(Configuration values,
		ActivityRecord starting, boolean deferResume,
		ActivityTaskManagerService.UpdateConfigurationResult result) {

	int changes = 0;
	boolean kept = true;

	mAtmService.deferWindowLayout();
	try {
		if (values != null) {
			if (mDisplayId == DEFAULT_DISPLAY) {
				// Override configuration of the default display duplicates global config, so
				// we're calling global config update instead for default display. It will also
				// apply the correct override config.
				changes = mAtmService.updateGlobalConfigurationLocked(values,
						false /* initLocale */, false /* persistent */,
						UserHandle.USER_NULL /* userId */);
			} else {
				changes = performDisplayOverrideConfigUpdate(values);
			}
		}

		if (!deferResume) {
			kept = mAtmService.ensureConfigAndVisibilityAfterUpdate(starting, changes);
		}
	} finally {
		mAtmService.continueWindowLayout();
	}

	if (result != null) {
		result.changes = changes;
		result.activityRelaunched = !kept;
	}
	return kept;
}

单个屏幕场景mDisplayId == DEFAULT_DISPLAY调用mAtmService.updateGlobalConfigurationLocked

platform/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

/** Update default (global) configuration and notify listeners about changes. */
int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
		boolean persistent, int userId) {

	mTempConfig.setTo(getGlobalConfiguration());
	final int changes = mTempConfig.updateFrom(values);
	if (changes == 0) {
		return 0;
	}

	...

	// Note: certain tests currently run as platform_app which is not allowed
	// to set debug system properties. To ensure that system properties are set
	// only when allowed, we check the current UID.
	if (Process.myUid() == Process.SYSTEM_UID) {
		if (values.mcc != 0) {
			SystemProperties.set("debug.tracing.mcc", Integer.toString(values.mcc));
		}
		if (values.mnc != 0) {
			SystemProperties.set("debug.tracing.mnc", Integer.toString(values.mnc));
		}
	}

	if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
		final LocaleList locales = values.getLocales();
		int bestLocaleIndex = 0;
		if (locales.size() > 1) {
			if (mSupportedSystemLocales == null) {
				mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
			}
			bestLocaleIndex = Math.max(0, locales.getFirstMatchIndex(mSupportedSystemLocales));
		}
		SystemProperties.set("persist.sys.locale",
				locales.get(bestLocaleIndex).toLanguageTag());
		LocaleList.setDefault(locales, bestLocaleIndex);
	}

	mTempConfig.seq = increaseConfigurationSeqLocked();

	Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempConfig);
	// TODO(multi-display): Update UsageEvents#Event to include displayId.
	mUsageStatsInternal.reportConfigurationChange(mTempConfig, mAmInternal.getCurrentUserId());

	// TODO: If our config changes, should we auto dismiss any currently showing dialogs?
	updateShouldShowDialogsLocked(mTempConfig);

	AttributeCache ac = AttributeCache.instance();
	if (ac != null) {
		ac.updateConfiguration(mTempConfig);
	}

	// Make sure all resources in our process are updated right now, so that anyone who is going
	// to retrieve resource values after we return will be sure to get the new ones. This is
	// especially important during boot, where the first config change needs to guarantee all
	// resources have that config before following boot code is executed.
	mSystemThread.applyConfigurationToResources(mTempConfig);

	if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
		final Message msg = PooledLambda.obtainMessage(
				ActivityTaskManagerService::sendPutConfigurationForUserMsg,
				this, userId, new Configuration(mTempConfig));
		mH.sendMessage(msg);
	}

	SparseArray<WindowProcessController> pidMap = mProcessMap.getPidMap();
	for (int i = pidMap.size() - 1; i >= 0; i--) {
		final int pid = pidMap.keyAt(i);
		final WindowProcessController app = pidMap.get(pid);
		ProtoLog.v(WM_DEBUG_CONFIGURATION, "Update process config of %s to new "
				+ "config %s", app.mName, mTempConfig);
		app.onConfigurationChanged(mTempConfig);
	}

	final Message msg = PooledLambda.obtainMessage(
			ActivityManagerInternal::broadcastGlobalConfigurationChanged,
			mAmInternal, changes, initLocale);
	mH.sendMessage(msg);

	Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RootConfigChange");
	// Update stored global config and notify everyone about the change.
	mRootWindowContainer.onConfigurationChanged(mTempConfig);
	Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);

	Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
	return changes;
}

调用所用进程对应WindowProcessControlleronConfigurationChanged方法 这个方法最终会通知到客户端应用的所有Activity、Service等。随后通过broadcastGlobalConfigurationChanged发送ACTION_CONFIGURATION_CHANGED广播最后调用mRootWindowContainer.onConfigurationChanged(mTempConfig);这个通知服务端RootWindowContainer及其所有子窗口进行configuration更新

客户端传递路线参考序列图最终调用ConfigurationControllerhandleConfigurationChanged

platform/frameworks/base/core/java/android/app/ConfigurationController.java

/**
 * Update the configuration to latest.
 * @param config The new configuration.
 * @param compat The new compatibility information.
 */
void handleConfigurationChanged(@Nullable Configuration config,
		@Nullable CompatibilityInfo compat) {
	int configDiff;
	boolean equivalent;

	// Get theme outside of synchronization to avoid nested lock.
	final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme();
	final ContextImpl systemUiContext = mActivityThread.getSystemUiContextNoCreate();
	final Resources.Theme systemUiTheme =
			systemUiContext != null ? systemUiContext.getTheme() : null;
	synchronized (mResourcesManager) {
		if (mPendingConfiguration != null) {
			if (!mPendingConfiguration.isOtherSeqNewer(config)) {
				config = mPendingConfiguration;
				updateDefaultDensity(config.densityDpi);
			}
			mPendingConfiguration = null;
		}

		if (config == null) {
			return;
		}

		// This flag tracks whether the new configuration is fundamentally equivalent to the
		// existing configuration. This is necessary to determine whether non-activity callbacks
		// should receive notice when the only changes are related to non-public fields.
		// We do not gate calling {@link #performActivityConfigurationChanged} based on this
		// flag as that method uses the same check on the activity config override as well.
		equivalent = mConfiguration != null && (0 == mConfiguration.diffPublicOnly(config));

		if (DEBUG_CONFIGURATION) {
			Slog.v(TAG, "Handle configuration changed: " + config);
		}

		final Application app = mActivityThread.getApplication();
		final Resources appResources = app.getResources();
		mResourcesManager.applyConfigurationToResources(config, compat);
		updateLocaleListFromAppContext(app.getApplicationContext());

		if (mConfiguration == null) {
			mConfiguration = new Configuration();
		}
		if (!mConfiguration.isOtherSeqNewer(config) && compat == null) {
			return;
		}

		configDiff = mConfiguration.updateFrom(config);
		config = applyCompatConfiguration();
		HardwareRenderer.sendDeviceConfigurationForDebugging(config);

		if ((systemTheme.getChangingConfigurations() & configDiff) != 0) {
			systemTheme.rebase();
		}

		if (systemUiTheme != null
				&& (systemUiTheme.getChangingConfigurations() & configDiff) != 0) {
			systemUiTheme.rebase();
		}
	}

	final ArrayList<ComponentCallbacks2> callbacks =
			mActivityThread.collectComponentCallbacks(false /* includeUiContexts */);

	freeTextLayoutCachesIfNeeded(configDiff);

	if (callbacks != null) {
		final int size = callbacks.size();
		for (int i = 0; i < size; i++) {
			ComponentCallbacks2 cb = callbacks.get(i);
			if (!equivalent) {
				performConfigurationChanged(cb, config);
			}
		}
	}
}

mResourcesManager.applyConfigurationToResources(config, compat);config更新resourceManager

configDiff = mConfiguration.updateFrom(config);config = applyCompatConfiguration();更新本地config让后通过performConfigurationChanged传导所有AcivityService

无论WindowProcessControlleronConfigurationChanged还是mRootWindowContainer.onConfigurationChanged 首先执行基类ConfigurationContaineronConfigurationChanged

platform/frameworks/base/services/core/java/com/android/server/wm/ConfigurationContainer.java

/**
 * Notify that parent config changed and we need to update full configuration.
 * @see #mFullConfiguration
 */
public void onConfigurationChanged(Configuration newParentConfig) {
	mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration);
	resolveOverrideConfiguration(newParentConfig);
	mFullConfiguration.setTo(newParentConfig);
	// Do not inherit always-on-top property from parent, otherwise the always-on-top
	// property is propagated to all children. In that case, newly added child is
	// always being positioned at bottom (behind the always-on-top siblings).
	mFullConfiguration.windowConfiguration.unsetAlwaysOnTop();
	mFullConfiguration.updateFrom(mResolvedOverrideConfiguration);
	onMergedOverrideConfigurationChanged();
	if (!mResolvedTmpConfig.equals(mResolvedOverrideConfiguration)) {
		// This depends on the assumption that change-listeners don't do
		// their own override resolution. This way, dependent hierarchies
		// can stay properly synced-up with a primary hierarchy's constraints.
		// Since the hierarchies will be merged, this whole thing will go away
		// before the assumption will be broken.
		// Inform listeners of the change.
		for (int i = mChangeListeners.size() - 1; i >= 0; --i) {
			mChangeListeners.get(i).onRequestedOverrideConfigurationChanged(
					mResolvedOverrideConfiguration);
		}
	}
	for (int i = mChangeListeners.size() - 1; i >= 0; --i) {
		mChangeListeners.get(i).onMergedOverrideConfigurationChanged(
				mMergedOverrideConfiguration);
	}
	for (int i = getChildCount() - 1; i >= 0; --i) {
		dispatchConfigurationToChild(getChildAt(i), mFullConfiguration);
	}
}

这个方法Configuration相关一些重要属性进行更新详述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1534392.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高级数据结构 <AVL树>

本文已收录至《数据结构(C/C语言)》专栏&#xff01; 作者&#xff1a;ARMCSKGT 目录 前言正文AVL树的性质AVL树的定义AVL树的插入函数左单旋右单旋右左双旋左右双旋 检验AVL树的合法性关于AVL树 最后 前言 前面我们学习了二叉树&#xff0c;普通的二叉树没有任何特殊性质&…

数据结构面试常见问题之Insert or Merge

&#x1f600;前言 本文将讨论如何区分插入排序和归并排序两种排序算法。我们将通过判断序列的有序性来确定使用哪种算法进行排序。具体而言&#xff0c;我们将介绍判断插入排序和归并排序的方法&#xff0c;并讨论最小和最大的能区分两种算法的序列长度。 &#x1f3e0;个人主…

pycorrector检测OCR错字实践

参考&#xff1a;https://github.com/shibing624/pycorrector/tree/master/examples/macbert stopwords.txt 添加专业停用词&#xff0c;避免错误 设置自定义词典&#xff0c;避免将正确的词错误检测成错误的词 from pycorrector import Corrector m Corrector() m.set_cus…

《由浅入深学习SAP财务》:第2章 总账模块 - 2.4 会计凭证处理

2.4.1 会计凭证处理的基本概念 会计凭证是企业经济业务在会计上的反映&#xff0c;它是用会计语言表达的一种单据。 典型生产企业的财务凭证创建方式&#xff1a; 企业在实施SAP的过程中&#xff0c;大部分凭证都是自动生成的。要保证这些凭证能准确地生成&#xff0c;必须要满…

mysql 数据库 基本介绍

一 数据 &#xff08;一&#xff09;数据是什么 描述事物的符号记录 包括数字&#xff0c;文字、图形、图像、声音、档案记录气 以“记录”形式按统一的格式进行存储 &#xff08;二&#xff09;数据的分类 1&#xff0c;结构化的数据 即有固定格式和有限长度的数据。例…

hcip复习总结1

OSI----------- 定义了数据的产生标准 。 7 层 应用 ------- 表示 会话 传输 -----Telnet - 23 ssh---22 http---80 https-443 TCP ---- 传输控制卋议。是一种面向连接的可靠的传输卋议。 UDP---- 用户数据报卋议。是一种非面向连接的丌可靠传输卋议。 保证可靠性&…

面向量产!基于视觉的速度距离估计

面向量产&#xff01;基于视觉的速度距离估计 论文名称&#xff1a;Vision-based Vehicle Speed Estimation: A Survey 导读 在精确检测车速车距的方案中&#xff0c;视觉方案是非常具有挑战性的&#xff0c;但由于没有昂贵的距离传感器而大幅降低成本&#xff0c;所以潜力巨…

国内智能驾驶芯片领先供应商地平线智能驾驶芯片介绍

地平线国内智能驾驶芯片领先供应商&#xff0c;由国际著名机器学习专家余凯博士于2015年7月创建&#xff1b;2017年12月&#xff0c;地平线即推出了首款 智能芯片征程1和旭日1&#xff1b;2019年8月&#xff0c;宣布量产中国首款车规级智能芯片征程2并于同年10月发 布新一代AIo…

【Git】第二课:git安装和配置

安装 我们伟大祖国有句古话叫巧妇难为无米之炊&#xff0c;还有句话叫工欲善其事必先利其器。所以&#xff0c;在正式的学习之前&#xff0c;我们需要先把git这把利器安装好。 Windows系统 下载安装包 打开Git - Downloading Package页面&#xff0c;根据系统类型32位还是6…

有ai写文案的工具吗?分享5款好用的工具!

在数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;已渗透到我们生活的方方面面&#xff0c;包括内容创作领域。AI写文案的软件以其高效、便捷的特点&#xff0c;正逐渐受到广大内容创作者、营销人员、甚至普通用户的青睐。本文将为您盘点几款热门的AI写文案软件&…

Zotero引入英文参考文献作者都是大写字母问题

修改之前是这样的&#xff1a; 修改过程 进入word 打开样式编辑器 打开后&#xff0c;找到这里&#xff1a; 删除 text-case“uppercase” 就可以实现这个样式&#xff1a; 然后我们点击保存&#xff0c;将这个样式文件另存为&#xff0c;然后替换掉原来的文件 源文件在 …

聚焦两会:数字化再加速,VR全景助力制造业转型

近年来&#xff0c;随着信息技术、人工智能、VR虚拟现实等新兴技术的不断涌现&#xff0c;数字化正日益成为推动当今经济发展的新驱动力。在不久前的两会上&#xff0c;数字化经济和创新技术再度成为热门话题&#xff1a; 国务院总理李强作政府工作报告&#xff1a; 要深入推…

误删了Linux系统的libm.so.6文件与libm-2.27.so的软链接导致的开机出现kernel panic的解决方案(图文U盘救援详细教程)

事情起因 最近在做嵌入式视觉&#xff0c;捣弄rknn3588&#xff0c;在推理过程中报了一个错&#xff0c;就是说我的GLIBC的版本太低了&#xff0c;我也没有多想&#xff0c;想着升一下版本就好了&#xff0c;然后找到了这篇博客。【请谨慎操作】Ubuntu18.04升级GLIBC_2.29&…

云效 AppStack + 阿里云 MSE 实现应用服务全链路灰度

作者&#xff1a;周静、吴宇奇、泮圣伟 在应用开发测试验证通过后、进行生产发布前&#xff0c;为了降低新版本发布带来的风险&#xff0c;期望能够先部署到灰度环境&#xff0c;用小部分业务流量进行全链路灰度验证&#xff0c;验证通过后再全量发布生产。本文主要介绍如何通…

Java学习笔记NO.25

T2.编写程序实现乐手弹奏乐器。乐手可以弹奏不同的乐器从而发出不同的声音。可以弹奏的乐器包括二胡、钢琴和琵琶。要求&#xff1a; (1)定义乐器类Instrument&#xff0c;包括方法makeSound() (2)定义乐器类的子类&#xff1a;二胡Erhu、钢琴Piano和小提琴Violin (3)定义乐手类…

2024年【T电梯修理】模拟考试及T电梯修理模拟考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 T电梯修理模拟考试是安全生产模拟考试一点通生成的&#xff0c;T电梯修理证模拟考试题库是根据T电梯修理最新版教材汇编出T电梯修理仿真模拟考试。2024年【T电梯修理】模拟考试及T电梯修理模拟考试题库 1、【多选题】…

PPT好看配色

放几个链接&#xff01;画图时候可以参考&#xff01;转自知乎 Color Hunt ColorDrop 中国色 Flat UI Colors Coolors

HBase Shell基本操作

一、进入Hbase Shell客户端 先在Linux Shell命令行终端执行start-dfs.sh脚本启动HDFS&#xff0c;再执行start-hbase.sh脚本启动HBase。如果Linux系统已配置HBase环境变量&#xff0c;可直接在任意目录下执行hbase shell脚本命令&#xff0c;就可进入HBase Shell的命令行终端环…

关于UDP协议

UDP协议是基于非连接的发送数据就是把数据包简单封装一下&#xff0c;然后从网卡发出去就可以&#xff0c;数据包之间没有状态上的联系&#xff0c;UDP处理方式简单&#xff0c;所以性能损耗非常少&#xff0c;对于CPU、内存资源的占用远小于TCP&#xff0c;但是对于网络传输过…

yank+mermaid+甘特图实例

因为notion对于mermaid支持很一般&#xff0c;尤其是甘特图&#xff0c;如果时间跨度大、节点多&#xff0c;字号会小到看不见&#xff0c;非常不方便。 同样的代码&#xff0c;在notion中如下图所示&#xff1a;&#xff08;下图是我的一份年度规划&#xff09; &#xff08;…