“无处不在” 的系统核心服务 —— ActivityManagerService 启动流程解析
本文基于 Android 9.0 , 代码仓库地址 : android_9.0.0_r45
系列文章目录:
文中相关源码链接:
之前介绍 SystemServer 启动流程 的时候说到,SystemServer 进程启动了一系列的系统服务,ActivityManagerService 是其中最核心的服务之一。它和四大组件的启动、切换、调度及应用进程的管理和调度息息相关,其重要性不言而喻。本文主要介绍其启动流程,它是在 SystemServer
的 main()
中启动的,整个启动流程经历了 startBootstrapServices
、startCoreService()
、startOtherService()
。下面就顺着源码来捋一捋 ActivityManagerService
的启动流程,下文中简称 AMS
。
private void startBootstrapServices() {
...
// 1. AMS 初始化
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
// 设置 AMS 的系统服务管理器
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
// 设置 AMS 的应用安装器
mActivityManagerService.setInstaller(installer);
...
mActivityManagerService.initPowerManagement();
...
// 2. AMS.setSystemProcess()
mActivityManagerService.setSystemProcess();
...
}
private void startCoreServices{
...
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
...
}
private void startherService{
...
// 3. 安装系统 Provider
mActivityManagerService.installSystemProviders();
...
final Watchdog watchdog = Watchdog.getInstance();
watchdog.init(context, mActivityManagerService);
...
mActivityManagerService.setWindowManager(wm);
...
networkPolicy = new NetworkPolicyManagerService(context, mActivityManagerService,
networkManagement);
...
if (safeMode) {
traceBeginAndSlog("EnterSafeModeAndDisableJitCompilation");
mActivityManagerService.enterSafeMode();
// Disable the JIT for the system_server process
VMRuntime.getRuntime().disableJitCompilation();
traceEnd();
}
...
mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
...
// 4. AMS.systemReady()
mActivityManagerService.systemReady(() -> {
...
mActivityManagerService.startObservingNativeCrashes();
}
}
AMS 初始化
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
AMS 通过 SystemServiceManager.startService()
方法初始化,startService()
在之前的文章中已经分析过,其作用是根据参数传入的类通过反射进行实例化,并回调其 onStart()
方法。注意这里传入的是 ActivityManagerService.Lifecycle.class
,LifeCycle
是 AMS 的一个静态内部类。
public static final class Lifecycle extends SystemService {
private final ActivityManagerService mService;
// 构造函数中新建 ActivityManagerService 对象
public Lifecycle(Context context) {
super(context);
mService = new ActivityManagerService(context);
}
@Override
public void onStart() {
mService.start();
}
@Override
public void onBootPhase(int phase) {
mService.mBootPhase = phase;
if (phase == PHASE_SYSTEM_SERVICES_READY) {
mService.mBatteryStatsService.systemServicesReady();
mService.mServices.systemServicesReady();
}
}
@Override
public void onCleanupUser(int userId) {
mService.mBatteryStatsService.onCleanupUser(userId);
}
public ActivityManagerService getService() {
return mService;
}
}
Lifecycle
的构造函数中初始化了 AMS。再来看看 AMS 的构造函数。
public ActivityManagerService(Context systemContext) {
mInjector = new Injector();
// AMS 上下文
mContext = systemContext;
mFactoryTest = FactoryTest.getMode();
// ActivityThread 对象
mSystemThread = ActivityThread.currentActivityThread();
// ContextImpl 对象
mUiContext = mSystemThread.getSystemUiContext();
mPermissionReviewRequired = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_permissionReviewRequired);
// 线程名为 ActivityManager 的前台线程,ServiceThread 继承于 HandlerThread
mHandlerThread = new ServiceThread(TAG,
THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
mHandlerThread.start();
// 获取 mHandlerThread 的 Handler 对象
mHandler = new MainHandler(mHandlerThread.getLooper());
// 创建名为 android.ui 的线程
mUiHandler = mInjector.getUiHandler(this);
// 不知道什么作用
mProcStartHandlerThread = new ServiceThread(TAG + ":procStart",
THREAD_PRIORITY_FOREGROUND, false /* allowIo */);
mProcStartHandlerThread.start();
mProcStartHandler = new Handler(mProcStartHandlerThread.getLooper());
mConstants = new ActivityManagerConstants(this, mHandler);
/* static; one-time init here */
// 根据优先级 kill 后台应用进程
if (sKillHandler == null) {
sKillThread = new ServiceThread(TAG + ":kill",
THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
sKillThread.start();
sKillHandler = new KillHandler(sKillThread.getLooper());
}
// 前台广播队列,超时时间为 10 秒
mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
"foreground", BROADCAST_FG_TIMEOUT, false);
// 后台广播队列,超时时间为 60 秒
mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
"background", BROADCAST_BG_TIMEOUT, true);
mBroadcastQueues[0] = mFgBroadcastQueue;
mBroadcastQueues[1] = mBgBroadcastQueue;
// 创建 ActiveServices
mServices = new ActiveServices(this);
mProviderMap = new ProviderMap(this);
// 创建 AppErrors,用于处理应用中的错误
mAppErrors = new AppErrors(mUiContext, this);
// 创建 /data/system 目录
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
systemDir.mkdirs();
mAppWarnings = new AppWarnings(this, mUiContext, mHandler, mUiHandler, systemDir);
// TODO: Move creation of battery stats service outside of activity manager service.
// 创建 BatteryStatsService,其信息保存在 /data/system/procstats 中
// 这里有个 TODO,打算把 BatteryStatsService 的创建移除 AMS
mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, mHandler);
mBatteryStatsService.getActiveStatistics().readLocked();
mBatteryStatsService.scheduleWriteToDisk();
mOnBattery = DEBUG_POWER ? true
: mBatteryStatsService.getActiveStatistics().getIsOnBattery();
mBatteryStatsService.getActiveStatistics().setCallback(this);
// 创建 ProcessStatsService,并将其信息保存在 /data/system/procstats 中
mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
mAppOpsService = mInjector.getAppOpsService(new File(systemDir, "appops.xml"), mHandler);
// 定义 ContentProvider 访问指定 Uri 数据的权限
mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"), "uri-grants");
// 多用户管理
mUserController = new UserController(this);
mVrController = new VrController(this);
// 获取 OpenGL 版本
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
if (SystemProperties.getInt("sys.use_fifo_ui", 0) != 0) {
mUseFifoUiScheduling = true;
}
mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
mConfigurationSeq = mTempConfig.seq = 1;
// 创建 ActivityStackSupervisor ,用于管理 Activity 任务栈
mStackSupervisor = createStackSupervisor();
mStackSupervisor.onConfigurationChanged(mTempConfig);
mKeyguardController = mStackSupervisor.getKeyguardController();
mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
mTaskChangeNotificationController =
new TaskChangeNotificationController(this, mStackSupervisor, mHandler);
// 创建 ActivityStartController 对象,用于管理 Activity 的启动
mActivityStartController = new ActivityStartController(this);
// 创建最近任务栈 RecentTask 对象
mRecentTasks = createRecentTasks();
mStackSupervisor.setRecentTasks(mRecentTasks);
mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mHandler);
mLifecycleManager = new ClientLifecycleManager();
// 创建 CpuTracker 线程,追踪 CPU 状态
mProcessCpuThread = new Thread("CpuTracker") {
@Override
public void run() {
synchronized (mProcessCpuTracker) {
mProcessCpuInitLatch.countDown();
mProcessCpuTracker.init(); // 初始化 ProcessCpuTracker。注意同步问题
}
while (true) {
try {
try {
synchronized(this) {
final long now = SystemClock.uptimeMillis();
long nextCpuDelay = (mLastCpuTime.get()+MONITOR_CPU_MAX_TIME)-now;
long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
//Slog.i(TAG, "Cpu delay=" + nextCpuDelay
// + ", write delay=" + nextWriteDelay);
if (nextWriteDelay < nextCpuDelay) {
nextCpuDelay = nextWriteDelay;
}
if (nextCpuDelay > 0) {
mProcessCpuMutexFree.set(true);
this.wait(nextCpuDelay);
}
}
} catch (InterruptedException e) {
}
// 更新 Cpu 统计信息
updateCpuStatsNow();
} catch (Exception e) {
Slog.e(TAG, "Unexpected exception collecting process stats", e);
}
}
}
};
// hidden api 设置
mHiddenApiBlacklist = new HiddenApiSettings(mHandler, mContext);
// 设置 Watchdog 监控
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
// bind background thread to little cores
// this is expected to fail inside of framework tests because apps can't touch cpusets directly
// make sure we've already adjusted system_server's internal view of itself first
// 更新进程的 oom_adj 值
updateOomAdjLocked();
try {
Process.setThreadGroupAndCpuset(BackgroundThread.get().getThreadId(),
Process.THREAD_GROUP_BG_NONINTERACTIVE);
} catch (Exception e) {
Slog.w(TAG, "Setting background thread cpuset failed");
}
}
AMS 的构造函数中做了很多事情,代码中作了很多注释,这里就不再展开细说了。
LifeCycle
的构造函数中初始化了 AMS,然后会调用 LifeCycle.onStart()
,最终调用的是 AMS.start()
方法。
private void start() {
// 移除所有进程组
removeAllProcessGroups();
// 启动构造函数中创建的 CpuTracker 线程,监控 cpu 使用情况
mProcessCpuThread.start();
// 启动 BatteryStatsService,统计电池信息
mBatteryStatsService.publish();
mAppOpsService.publish(mContext);
// 启动 LocalService ,将 ActivityManagerInternal 加入服务列表
LocalServices.addService(ActivityManagerInternal.class, new LocalService());
// 等待 mProcessCpuThread 线程中的同步代码块执行完毕。
// 在执行 mProcessCpuTracker.init() 方法时访问 mProcessCpuTracker 将阻塞
try {
mProcessCpuInitLatch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException("Interrupted wait during start");
}
}
AMS 的初始化工作到这里就基本结束了,我们再回到 startBootstrapServices()
中,看看 AMS 的下一步动作 setSystemProcess()
。
AMS.setSystemProcess()
public void setSystemProcess() {
try {
// 注册各种服务
// 注册 AMS
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
// 注册进程统计服务
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
// 注册内存信息服务
ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_HIGH);
// 注册 GraphicsBinder
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
// 注册 DbBinder
ServiceManager.addService("dbinfo", new DbBinder(this));
if (MONITOR_CPU_USAGE) {
// 注册 DbBinder
ServiceManager.addService("cpuinfo", new CpuBinder(this),
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
}
// 注册权限管理者 PermissionController
ServiceManager.addService("permission", new PermissionController(this
// 注册进程信息服务 ProcessInfoService
ServiceManager.addService("processinfo", new ProcessInfoService(this));
// 获取包名为 android 的应用信息,framework-res.apk
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
"android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY);
mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
synchronized (this) {
// 创建 ProcessRecord
ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
app.persistent = true;
app.pid = MY_PID;
app.maxAdj = ProcessList.SYSTEM_ADJ;
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.put(app.pid, app);
}
// 更新 mLruProcesses
updateLruProcessLocked(app, false, null);
// 更新进程对应的 oom_adj 值
updateOomAdjLocked();
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
"Unable to find android system package", e);
}
// Start watching app ops after we and the package manager are up and running.
// 当 packager manager 启动并运行时开始监听 app ops
mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_IN_BACKGROUND, null,
new IAppOpsCallback.Stub() {
@Override public void opChanged(int op, int uid, String packageName) {
if (op == AppOpsManager.OP_RUN_IN_BACKGROUND && packageName != null) {
if (mAppOpsService.checkOperation(op, uid, packageName)
!= AppOpsManager.MODE_ALLOWED) {
runInBackgroundDisabled(uid);
}
}
}
});
}
setSystemProcess()
的主要工作就是向 ServiceManager 注册关联的系统服务。
AMS.installSystemProviders()
public final void installSystemProviders() {
List<ProviderInfo> providers;
synchronized (this) {
ProcessRecord app = mProcessNames.get("system", SYSTEM_UID);
providers = generateApplicationProvidersLocked(app);
if (providers != null) {
for (int i=providers.size()-1; i>=0; i--) {
ProviderInfo pi = (ProviderInfo)providers.get(i);
if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
Slog.w(TAG, "Not installing system proc provider " + pi.name
+ ": not system .apk");
// 移除非系统 Provier
providers.remove(i);
}
}
}
}
// 安装系统 Provider
if (providers != null) {
mSystemThread.installSystemProviders(providers);
}
synchronized (this) {
mSystemProvidersInstalled = true;
}
mConstants.start(mContext.getContentResolver());
// 创建 CoreSettingsObserver ,监控核心设置的变化
mCoreSettingsObserver = new CoreSettingsObserver(this);
// 创建 FontScaleSettingObserver,监控字体的变化
mFontScaleSettingObserver = new FontScaleSettingObserver();
// 创建 DevelopmentSettingsObserver
mDevelopmentSettingsObserver = new DevelopmentSettingsObserver();
GlobalSettingsToPropertiesMapper.start(mContext.getContentResolver());
// Now that the settings provider is published we can consider sending
// in a rescue party.
RescueParty.onSettingsProviderPublished(mContext);
//mUsageStatsService.monitorPackages();
}
installSystemProviders()
的主要工作是安装系统 Proviers。
AMS.systemReady()
AMS.systemReady()
是 AMS 启动流程的最后一步了。
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
...
synchronized(this) {
if (mSystemReady) { // 首次调用 mSystemReady 为 false
// If we're done calling all the receivers, run the next "boot phase" passed in
// by the SystemServer
if (goingCallback != null) {
goingCallback.run();
}
return;
}
// 一系列 systemReady()
mHasHeavyWeightFeature = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CANT_SAVE_STATE);
mLocalDeviceIdleController
= LocalServices.getService(DeviceIdleController.LocalService.class);
mAssistUtils = new AssistUtils(mContext);
mVrController.onSystemReady();
// Make sure we have the current profile info, since it is needed for security checks.
mUserController.onSystemReady();
mRecentTasks.onSystemReadyLocked();
mAppOpsService.systemReady();
mSystemReady = true;
}
...
ArrayList<ProcessRecord> procsToKill = null;
synchronized(mPidsSelfLocked) {
for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
ProcessRecord proc = mPidsSelfLocked.valueAt(i);
if (!isAllowedWhileBooting(proc.info)){
if (procsToKill == null) {
procsToKill = new ArrayList<ProcessRecord>();
}
procsToKill.add(proc);
}
}
}
synchronized(this) {
if (procsToKill != null) {
for (int i=procsToKill.size()-1; i>=0; i--) {
ProcessRecord proc = procsToKill.get(i);
removeProcessLocked(proc, true, false, "system update done");
}
}
// Now that we have cleaned up any update processes, we
// are ready to start launching real processes and know that
// we won't trample on them any more.
mProcessesReady = true;
}
...
if (goingCallback != null) goingCallback.run();
mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
Integer.toString(currentUserId), currentUserId);
mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
Integer.toString(currentUserId), currentUserId);
// 回调所有 SystemService 的 onStartUser() 方法
mSystemServiceManager.startUser(currentUserId);
synchronized (this) {
// Only start up encryption-aware persistent apps; once user is
// unlocked we'll come back around and start unaware apps
startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
// Start up initial activity.
mBooting = true;
// Enable home activity for system user, so that the system can always boot. We don't
// do this when the system user is not setup since the setup wizard should be the one
// to handle home activity in this case.
if (UserManager.isSplitSystemUser() &&
Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0) != 0) {
ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);
try {
AppGlobals.getPackageManager().setComponentEnabledSetting(cName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,
UserHandle.USER_SYSTEM);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
// 启动桌面 Home 应用
startHomeActivityLocked(currentUserId, "systemReady");
...
long ident = Binder.clearCallingIdentity();
try {
// 发送广播 USER_STARTED
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID,
currentUserId);
// 发送广播 USER_STARTING
intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
broadcastIntentLocked(null, null, intent,
null, new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser)
throws RemoteException {
}
}, 0, null, null,
new String[] {INTERACT_ACROSS_USERS}, OP_NONE,
null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
} catch (Throwable t) {
Slog.wtf(TAG, "Failed sending first user broadcasts", t);
} finally {
Binder.restoreCallingIdentity(ident);
}
mStackSupervisor.resumeFocusedStackTopActivityLocked();
mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
BinderInternal.nSetBinderProxyCountWatermarks(6000,5500);
BinderInternal.nSetBinderProxyCountEnabled(true);
BinderInternal.setBinderProxyCountCallback(
new BinderInternal.BinderProxyLimitListener() {
@Override
public void onLimitReached(int uid) {
if (uid == Process.SYSTEM_UID) {
Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
} else {
killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
"Too many Binders sent to SYSTEM");
}
}
}, mHandler);
}
}
systemReady()
方法源码很长,上面做了很多删减。注意其中的 startHomeActivityLocked()
方法会启动桌面 Activity 。
boolean startHomeActivityLocked(int userId, String reason) {
...
Intent intent = getHomeIntent();
ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
if (aInfo != null) {
intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
// Don't do this if the home app is currently being
// instrumented.
aInfo = new ActivityInfo(aInfo);
aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid, true);
if (app == null || app.instr == null) {
intent.setFlags(intent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
// For ANR debugging to verify if the user activity is the one that actually
// launched.
final String myReason = reason + ":" + userId + ":" + resolvedUserId;
// 启动桌面 Activity
mActivityStartController.startHomeActivity(intent, aInfo, myReason);
}
} else {
Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
}
return true;
}
ActivityStartController
负责启动 Activity,至此,桌面应用就启动了。
最后
整篇写下来感觉就像小学生流水日记一样,但是读源码,就像有钱人的生活一样,往往是那么朴实无华,且枯燥。我不经意间看了看我的劳力士,太晚了,时序图后面再补上吧!
最后,下集预告,接着这篇,Activity
的启动流程分析,敬请期待!
文章首发微信公众号:
秉心说
, 专注 Java 、 Android 原创知识分享,LeetCode 题解。更多最新原创文章,扫码关注我吧!
“无处不在” 的系统核心服务 —— ActivityManagerService 启动流程解析的更多相关文章
- (转)CentOS 7系统详细开机启动流程和关机流程
CentOS 7系统详细开机启动流程和关机流程 原文:http://blog.csdn.net/yuesichiu/article/details/51350654 名称 bootup - 系统启动流 ...
- Android系统之LK启动流程分析(一)
1.前言 LK是Little Kernel的缩写,在Qualcomm平台的Android系统中普遍采用LK作为bootloader,它是一个开源项目,LK是整个系统的引导部分,所以不是独立存在的,但是 ...
- EurekaClient自动装配及启动流程解析
在上篇文章中,我们简单介绍了EurekaServer自动装配及启动流程解析,本篇文章则继续研究EurekaClient的相关代码 老规矩,先看spring.factories文件,其中引入了一个配置类 ...
- Linux系统入门---开机启动流程
目录 Linux系统入门---开机启动流程 一.centos6 二.systemd管理进程 1.查看级别 三.centos7实践案例: 1.案例1:centos7系统,单用户修改root密码 案例2: ...
- 史上最全且最简洁易懂的Activity启动流程解析
Activity的启动流程是一个资深Android工程师必须掌握的内容,也是高职级面试中的高频面试知识点,无论是从事应用层开发,还是Framework开发,其重要性都无需我多言.而要真正理解它,就不可 ...
- SpringBoot启动流程解析
写在前面: 由于该系统是底层系统,以微服务形式对外暴露dubbo服务,所以本流程中SpringBoot不基于jetty或者tomcat等容器启动方式发布服务,而是以执行程序方式启动来发布(参考下图ke ...
- 插件占坑,四大组件动态注册前奏(二) 系统Service的启动流程
转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52203903 前言:为什么要了解系统Activity,Service,BroadCas ...
- 插件占坑,四大组件动态注册前奏(一) 系统Activity的启动流程
转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52190050 前言:为什么要了解系统Activity,Service,,BroadCa ...
- Centos7系统详细的启动流程
熟悉系统启动流程对于我们学习Linux系统是非常有帮助的,虽然基础,但能帮助我们更加理解Linux系统的工作机制.以下将以CentOS发行版为例来介绍Linux系统的启动流程,因为在CentOS 5. ...
随机推荐
- Apache Hadoop集群安装(NameNode HA + YARN HA + SPARK + 机架感知)
1.主机规划 序号 主机名 IP地址 角色 1 nn-1 192.168.9.21 NameNode.mr-jobhistory.zookeeper.JournalNode 2 nn-2 192.16 ...
- [C++]面向对象的程序设计——重要概念
1.面向对象程序设计的核心思想是数据抽象.继承和动态绑定.通过使用数据抽象可以将类的接口与实现分离:使用继承,可以定义相似的类型并对其相似的关系建模:使用动态绑定,可以在一定程度上忽略相似类型的区 ...
- [LeetCode]sum合集
LeetCode很喜欢sum,里面sum题一堆. 1.Two Sum Given an array of integers, return indices of the two numbers suc ...
- sql server 使用 partition by 分区函数 解决不连续数字查询问题
sql server表中的某一列数据为不一定连续的数字,但是需求上要求按照连续数字来分段显示,如:1,2,3,4,5,6,10,11,12,13, 会要求这样显示:1~6,10~13.下面介绍如何实现 ...
- 建议收藏 - 专业的MySQL开发规范
为了项目的稳定,代码的高效,管理的便捷,在开发团队内部会制定各种各样的规范 这里分享一份我们定义的MySQL开发规范,欢迎交流拍砖 数据库对象命名规范 数据库对象 命名规范的对象是指数据库SCHEMA ...
- Docker下实战zabbix三部曲之二:监控其他机器
在上一章<Docker下实战zabbix三部曲之一:极速体验>中,我们快速安装了zabbix server,并登录管理页面查看了zabbix server所在机器的监控信息,但是在实际场景 ...
- Python简单的抓取静态网页内容
import requests from bs4 import BeautifulSoup res = requests.get('http://news.sina.com.cn/china/')#获 ...
- Linux之修改系统密码
目录 Linux之修改系统密码 参考 RHEL6修改系统密码 RHEL7修改系统密码 Linux之修改系统密码
- BERT论文解读
本文尽量贴合BERT的原论文,但考虑到要易于理解,所以并非逐句翻译,而是根据笔者的个人理解进行翻译,其中有一些论文没有解释清楚或者笔者未能深入理解的地方,都有放出原文,如有不当之处,请各位多多包含,并 ...
- 面试|简单描述MySQL中,索引,主键,唯一索引,联合索引 的区别,对数据库的性能有什么影响(从读写两方面)
索引是一种特殊的文件(InnoDB 数据表上的索引是表空间的一个组成部分),它们 包含着对数据表里所有记录的引用指针. 普通索引(由关键字 KEY 或 INDEX 定义的索引)的唯一任务是加快对数据的 ...