[Android5.1]ActivityManagerService启动过程分析
ActivityManagerService(简称AMS)是Android系统的关键服务之中的一个。它的主要作用例如以下:
- 管理系统中全部应用进程的整个生命周期
- 管理应用进程中的Activity、Service、Broadcast和ContentProvider
- 内存管理,低内存释放等
AMS是一个服务端,定义了IBinder接口。其它的进程能够通过Binder机制与AMS进行通信。
AMS由system_server进程启动的,并作为一个独立线程执行在system_server进程中。
以下就简略分析一下AMS的启动过程
system_server启动AMS
PATH:frameworks/base/services/java/com/android/server/SystemServer.java
启动过程大致例如以下:
SystemServer.main()–>SystemServer.run()。
private void run() {
......
startBootstrapServices();
startOtherServices();
......
}
private void startBootstrapServices() {
......
// 启动AMS服务
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
// 初始化AMS的成员变量mSystemServiceManager
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
// 初始化AMS的成员变量mInstaller
mActivityManagerService.setInstaller(installer);
......
// 主要是创建system_server相应的ProcessRecord,并初始化
mActivityManagerService.setSystemProcess();
......
}
private void startOtherServices() {
......
// 主要是创建并注冊SettingsProvider
mActivityManagerService.installSystemProviders();
......
// 系统启动前的准备工作,启动SystemUI和Home界面等
mActivityManagerService.systemReady(new Runnable() {...});
}
重点看一下mSystemServiceManager.startService():
public SystemService startService(String className) {
final Class<SystemService> serviceClass;
try {
serviceClass = (Class<SystemService>)Class.forName(className);
} catch (ClassNotFoundException ex) {
......
}
return startService(serviceClass);
}
public <T extends SystemService> T startService(Class<T> serviceClass) {
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
// Create the service.
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
//创建ActivityManagerService.Lifecycle对象
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
......
}
// 加入到成员变量mServices中
mServices.add(service);
// Start it.
try {
// 执行ActivityManagerService.Lifecycle.onStart()
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + name
+ ": onStart threw an exception", ex);
}
return service;
}
ActivityManagerService.Lifecycle
PATH:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public static final class Lifecycle extends SystemService {
private final ActivityManagerService mService;
public Lifecycle(Context context) {
super(context);
// 创建ActivityManagerServiceEx对象
mService = new ActivityManagerServiceEx(context);
}
@Override
public void onStart() {
mService.start(); //执行ActivityManagerServiceEx.start()
}
public ActivityManagerService getService() {
return mService;
}
}
当中,ActivityManagerServiceEx是ActivityManagerService的子类,定义例如以下:
public final class ActivityManagerServiceEx extends ActivityManagerService {
......
public ActivityManagerServiceEx(Context systemContext) {
super(systemContext);
mIsInHome = true;
}
......
}
这样,在new ActivityManagerServiceEx()时候。会调用到其父类ActivityManagerService的构造函数。
ActivityManagerService构造函数
PATH:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public ActivityManagerService(Context systemContext) {
mContext = systemContext;
mFactoryTest = FactoryTest.getMode();
mSystemThread = ActivityThread.currentActivityThread();
Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
//创建名称为“ActivityManager”的消息循环线程。
mHandlerThread = new ServiceThread(TAG,
android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
mHandlerThread.start();
//将该线程绑定到MainHandler,由MainHandler完毕消息的处理
mHandler = new MainHandler(mHandlerThread.getLooper());
//创建前台广播接收器,执行超时为10s
mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
"foreground", BROADCAST_FG_TIMEOUT, false);
//创建后台广播接收器。执行超时为60s
mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
"background", BROADCAST_BG_TIMEOUT, true);
mBroadcastQueues[0] = mFgBroadcastQueue;
mBroadcastQueues[1] = mBgBroadcastQueue;
mServices = new ActiveServicesEx(this);
mProviderMap = new ProviderMap(this);
//新建/data/system文件夹
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
systemDir.mkdirs();
//创建BatteryStatsService服务
mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
mBatteryStatsService.getActiveStatistics().readLocked();
mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
mOnBattery = DEBUG_POWER ?
true
: mBatteryStatsService.getActiveStatistics().getIsOnBattery();
mBatteryStatsService.getActiveStatistics().setCallback(this);
//创建ProcessStatsService服务
mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
//创建AppOpsService服务
mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler);
//创建AtomicFile文件
mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
// User 0 is the first and only user that runs at boot.
mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
mUserLru.add(Integer.valueOf(0));
updateStartedUserArrayLocked();
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
mConfiguration.setToDefaults();
mConfiguration.locale = Locale.getDefault();
mConfigurationSeq = mConfiguration.seq = 1;
mProcessCpuTracker.init();
mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
mStackSupervisor = new ActivityStackSupervisor(this);
mTaskPersister = new TaskPersister(systemDir, mStackSupervisor);
mProcessCpuThread = new Thread("CpuTracker") {
@Override
public void run() {
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) {
}
updateCpuStatsNow();
} catch (Exception e) {
Slog.e(TAG, "Unexpected exception collecting process stats", e);
}
}
}
};
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
}
首先,创建了一个名为“ActivityManager”的消息循环线程,不断地接收其它进程发给AMS的消息;并把该消息循环线程与MainHandler绑定,这样,由MainHandler完毕消息的详细处理。
然后,创建了一些服务,并在/data/system文件夹下创建该服务须要的文件或文件夹,详细例如以下:
服务 | 服务说明 | 文件 | 文件说明 |
---|---|---|---|
BatteryStatsService | 电池状态管理 | /data/system/batterystats.bin | 记录包含电压在内的各种电池信息 |
ProcessStatsService | 进程状态管理 | /data/system/procstats | 记录各个进程的状态信息 |
AppOpsService | 应用操作权限管理 | /data/system/appops.xml | 存储各个app的权限设置和操作信息 |
另外,还创建了一个AtomicFile类型的文件mGrantFile ,文件路径为/data/system/urigrants.xml。
AtomicFile文件是通过创建一个备份文件来执行原子性操作的帮助类,保证文件读写的完整。
这样。system_server就完毕AMS的构造和启动。
回到system_server中,我们看到又调用了AMS的setSystemProcess方法。以下就分析一下该方法。
ActivityManagerService.setSystemProcess
public void setSystemProcess() {
try {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this));
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
if (MONITOR_CPU_USAGE) {
ServiceManager.addService("cpuinfo", new CpuBinder(this));
}
ServiceManager.addService("permission", new PermissionController(this));
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
"android", STOCK_PM_FLAGS);
mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
synchronized (this) {
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);
mProcessNames.put(app.processName, app.uid, app);
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.put(app.pid, app);
}
updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
"Unable to find android system package", e);
}
}
首先,向SystemServiceManager中加入了若干个服务:
服务 | 服务说明 |
---|---|
activity | AMS服务本身 |
procstats | 进程状态管理 |
meminfo | 获取内存信息 |
gfxinfo | 监控分析GPU profiling信息 |
dbinfo | 数据库相关服务 |
cpuinfo | 获取cpu相关信息 |
permission | 权限控制相关服务 |
然后。调用PMS的getApplicationInfo接口,获取名为”android”的应用程序信息。包名为”android”的apk即/system/framework/framework-res.apk。里面保存着系统GUI美化的相关文件,包含图标,弹出对话框的样式,动作特效,界面布局等。调用installSystemApplicationInfo载入framework-res.apk文件。
接着,调用newProcessRecordLocked新建一个ProcessRecord 对象app。ProcessRecord用来描写叙述一个进程的全部信息,包含该进程的全部activity和service等。在这里就是system_server(AMS就是在system_server进程中执行的)。
创建后,对app的一些成员变量进行初始化。包含设置为常驻内存执行;设置system_server的pid等。
最后。调用mProcessNames.put()将创建的ProcessRecord 对象app加入到ProcessMap< ProcessRecord >类型的成员变量mProcessNames中。
这里。app.processName=“system”。
这样,AMS就得到了system_server的ProcessRecord,以后AMS也能够管理system_server了。
继续回到system_server中。我们看到又调用了AMS的installSystemProviders方法,以下就分析一下该方法。
ActivityManagerService.installSystemProviders
public final void installSystemProviders() {
List<ProviderInfo> providers;
synchronized (this) {
ProcessRecord app = mProcessNames.get("system", Process.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");
providers.remove(i);
}
}
}
}
if (providers != null) {
mSystemThread.installSystemProviders(providers);
}
mCoreSettingsObserver = new CoreSettingsObserver(this);
//mUsageStatsService.monitorPackages();
}
首先,取出在setSystemProcess()中put到mProcessNames中的ProcessRecord对象app,即system_server的进程信息。
然后,调用generateApplicationProvidersLocked:
private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
List<ProviderInfo> providers = null;
try {
providers = AppGlobals.getPackageManager().
queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
} catch (RemoteException ex) {
}
if (DEBUG_MU)
Slog.v(TAG_MU, "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
int userId = app.userId;
if (providers != null) {
int N = providers.size();
app.pubProviders.ensureCapacity(N + app.pubProviders.size());
for (int i=0; i<N; i++) {
ProviderInfo cpi =
(ProviderInfo)providers.get(i);
boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags);
if (singleton && UserHandle.getUserId(app.uid) != 0) {
providers.remove(i);
N--;
i--;
continue;
}
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
if (cpr == null) {
cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
mProviderMap.putProviderByClass(comp, cpr);
}
if (DEBUG_MU)
Slog.v(TAG_MU, "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
app.pubProviders.put(cpi.name, cpr);
if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
mProcessStats);
}
ensurePackageDexOpt(cpi.applicationInfo.packageName);
}
}
return providers;
}
首先,调用PMS的queryContentProviders查找processName=“system”和uid=SYSTEM_UID的provider。即SettingsProvider。并获取其ProviderInfo 。
然后新建一个ContentProviderRecord(描写叙述一个ContentProvider,这里为SettingsProvider),并加入到AMS的成员变量mProviderMap和ProcessRecord对象的pubProviders中。
最后将SettingsProvider所在的package加入到ProcessRecord对象的pkglist中。
继续回到installSystemProviders()。调用installSystemProviders,先创建后注冊SettingsProvider。这样,其它进程就能够调用SettingsProvider。查询或改动一些系统设置了。
在installSystemProviders()的最后,注冊一个ContentObserver来监听SettingsProvider中的状态变化。
继续回到system_server中。我们看到又调用了AMS的systemReady方法。以下就分析一下该方法。
ActivityManagerService.systemReady
该函数主要完毕了以下几件事:
- 在当前执行的进程中,查找在systemReady之前不同意启动的进程。然后调用removeProcessLocked()终止该进程并释放资源。推断条件例如以下:
boolean isAllowedWhileBooting(ApplicationInfo ai) {
return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
}
- 载入若干配置信息和资源信息,代码例如以下:
retrieveSettings();
loadResourcesOnSystemReady();
private void retrieveSettings() {
final ContentResolver resolver = mContext.getContentResolver();
String debugApp = Settings.Global.getString(
resolver, Settings.Global.DEBUG_APP);
boolean waitForDebugger = Settings.Global.getInt(
resolver, Settings.Global.WAIT_FOR_DEBUGGER, 0) != 0;
boolean alwaysFinishActivities = Settings.Global.getInt(
resolver, Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
boolean forceRtl = Settings.Global.getInt(
resolver, Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0;
......
}
private void loadResourcesOnSystemReady() {
final Resources res = mContext.getResources();
mHasRecents = res.getBoolean(com.android.internal.R.bool.config_hasRecents);
mThumbnailWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
mThumbnailHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
}
- 调用回调函数goingCallback.run()。主要完毕两件事:执行其它系统服务的systemready()或systemRunning();启动SystemUI。
goingCallback.run()的实如今systemserver.java中:
mActivityManagerService.systemReady(new Runnable() {
@Override
public void run() {
Slog.i(TAG, "Making services ready");
mSystemServiceManager.startBootPhase(
SystemService.PHASE_ACTIVITY_MANAGER_READY);
try {
mActivityManagerService.startObservingNativeCrashes();
} catch (Throwable e) {
reportWtf("observing native crashes", e);
}
Slog.i(TAG, "WebViewFactory preparation");
WebViewFactory.prepareWebViewInSystemServer();
try {
startSystemUi(context); //启动SystemUI
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
try {
if (mountServiceF != null) mountServiceF.systemReady();
} catch (Throwable e) {
reportWtf("making Mount Service ready", e);
}
try {
if (networkScoreF != null) networkScoreF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Score Service ready", e);
}
try {
if (networkManagementF != null) networkManagementF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Managment Service ready", e);
}
try {
if (networkStatsF != null) networkStatsF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Stats Service ready", e);
}
try {
if (networkPolicyF != null) networkPolicyF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Policy Service ready", e);
}
try {
if (connectivityF != null) connectivityF.systemReady();
} catch (Throwable e) {
reportWtf("making Connectivity Service ready", e);
}
try {
if (audioServiceF != null) audioServiceF.systemReady();
} catch (Throwable e) {
reportWtf("Notifying AudioService running", e);
}
Watchdog.getInstance().start();
// It is now okay to let the various system services start their
// third party code...
mSystemServiceManager.startBootPhase(
SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
try {
if (wallpaperF != null) wallpaperF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying WallpaperService running", e);
}
try {
if (immF != null) immF.systemRunning(statusBarF);
} catch (Throwable e) {
reportWtf("Notifying InputMethodService running", e);
}
try {
if (locationF != null) locationF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying Location Service running", e);
}
try {
if (countryDetectorF != null) countryDetectorF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying CountryDetectorService running", e);
}
try {
if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying NetworkTimeService running", e);
}
try {
if (commonTimeMgmtServiceF != null) {
commonTimeMgmtServiceF.systemRunning();
}
} catch (Throwable e) {
reportWtf("Notifying CommonTimeManagementService running", e);
}
try {
if (textServiceManagerServiceF != null)
textServiceManagerServiceF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying TextServicesManagerService running", e);
}
try {
if (atlasF != null) atlasF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying AssetAtlasService running", e);
}
try {
// TODO(BT) Pass parameter to input manager
if (inputManagerF != null) inputManagerF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying InputManagerService running", e);
}
try {
if (telephonyRegistryF != null) telephonyRegistryF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying TelephonyRegistry running", e);
}
try {
if (mediaRouterF != null) mediaRouterF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying MediaRouterService running", e);
}
if (SystemProperties.get("persist.support.securetest").equals("1")) {
if (securityF != null) {
try {
securityF.systemReady(context);
} catch (Throwable e) {
reportWtf("Security Service ready", e);
}
}
}
}
});
- 调用addAppLocked启动那些声明为“FLAG_SYSTEM|FLAG_PERSISTENT”的应用程序:
final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
String abiOverride) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(info.processName, info.uid, true);
} else {
......
}
......
// This package really, really can not be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
info.packageName, false, UserHandle.getUserId(app.uid));
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ info.packageName + ": " + e);
}
//推断条件
if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
== (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
app.persistent = true;
app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
}
//假设该app的IApplicationThread等于null,而且没有在ArrayList<ProcessRecord>类型
//的成员变量mPersistentStartingProcesses中,
//启动该app,并把它加入到mPersistentStartingProcesses中。
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
startProcessLocked(app, "added application", app.processName, abiOverride,
null /* entryPoint */, null /* entryPointArgs */);
}
return app;
}
- 广播两个消息:ACTION_USER_STARTED和ACTION_USER_STARTING。标识用户已经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, mCurrentUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
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,
INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,
true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
} catch (Throwable t) {
......
- 调用startHomeActivityLocked()启动HOME界面。
这样,ActivityManagerService的启动和初始化就完毕了。
[Android5.1]ActivityManagerService启动过程分析的更多相关文章
- 开机SystemServer到ActivityManagerService启动过程分析
开机SystemServer到ActivityManagerService启动过程 一 从Systemserver到AMS zygote-> systemserver:java入层口: /** ...
- ActivityManagerService启动过程分析
之前讲Android的View的绘制原理和流程的时候,讲到过在Android调用setContentView之后,Android调用了一个prepreTravle的方法,这里面就提到了Activity ...
- Activity启动过程分析
Android的四大组件中除了BroadCastReceiver以外,其他三种组件都必须在AndroidManifest中注册,对于BroadCastReceiver来说,它既可以在AndroidMa ...
- startActivity启动过程分析(转)
基于Android 6.0的源码剖析, 分析android Activity启动流程,相关源码: frameworks/base/services/core/java/com/android/serv ...
- ASP.Net Core MVC6 RC2 启动过程分析[偏源码分析]
入口程序 如果做过Web之外开发的人,应该记得这个是标准的Console或者Winform的入口.为什么会这样呢? .NET Web Development and Tools Blog ASP.NE ...
- 【Android】应用程序Activity启动过程分析
在Android系统中,有两种操作会引发Activity的启动,一种用户点击应用程序图标时,Launcher会为我们启动应用程序的主Activity:应用程序的默认Activity启动起来后,它又可以 ...
- Neutron分析(2)——neutron-server启动过程分析
neutron-server启动过程分析 1. /etc/init.d/neutron-server DAEMON=/usr/bin/neutron-server DAEMON_ARGS=" ...
- linux视频学习7(ssh, linux启动过程分析,加解压缩,java网络编程)
回顾数据库mysql的备份和恢复: show databases; user spdb1; show tables; 在mysql/bin目录下 执行备份: ./mysqldump -u root - ...
- Spark Streaming应用启动过程分析
本文为SparkStreaming源码剖析的第三篇,主要分析SparkStreaming启动过程. 在调用StreamingContext.start方法后,进入JobScheduler.start方 ...
随机推荐
- Rails + rabl
当我们使用rails generate scaffold的方式生成MVC的时候,rails会自己主动给我们生成一系列的文件,包含了怎样用json显示model的view.这样事实上默认了你的系统是一个 ...
- 转:mac环境下使用svn
在Windows环境中,我们一般使用TortoiseSVN来搭建svn环境.在Mac环境下,由于Mac自带了svn的服务器端和客户端功能,所以我们可以在不装任何第三方软件的前提下使用svn功能,不过还 ...
- java使用默认线程池踩过的坑(二)
云智慧(北京)科技有限公司 陈鑫 是的.一个线程不可以启动两次.那么它是怎么推断的呢? public synchronized void start() { /** * A zero status v ...
- 76.Nodejs Express目录结构
转自:https://blog.csdn.net/xiaoxiaoqiye/article/details/51160262 Express是一个基于Node.js平台的极简.灵活的web应用开发框架 ...
- 50.Node.js 连接 MySQL
转自:http://www.runoob.com/nodejs/nodejs-express-framework.html 安装驱动 本教程使用了淘宝定制的 cnpm 命令进行安装: $ cnpm i ...
- 通过PXE安装Linux实况
通过PXE安装Linux实况 网卡引导操作系统的过程我们可以把它称为PXE(Pre-bootExecutionEnvironment),十几年前,在搞无盘NT时候,我们为了使网卡支持PXE引导要特意购 ...
- DG的数据保护模式
DG的数据保护模式 数据保护膜有三种: – Maximum protection – Maximum availability – Maximum performance Maximum protec ...
- 韦东山ARM裸机笔记(2)--vi编辑器
VI编辑器(Visual Interface--可视化接口) 一.Linux下的一个文本编辑器,所具备的基本功能: 打开.新建.保存文件 光标移动 文本编辑 (多行间 | 多列间)复制.粘贴.删除 查 ...
- PHP生成二维码方法
<?php //先下载一份phpqrcode类,下载地址http://down.51cto.com/data/780947require_once("phpqrcode/phpqrco ...
- POJ 1118 Lining Up 直线穿过最多的点数
http://poj.org/problem?id=1118 直接枚举O(n^3) 1500ms能过...数据太水了...这个代码就不贴了... 斜率排序O(n^2logn)是更好的做法...枚举斜率 ...