菜鸟学Android源码-System Server服务启动(Launcher调起)

2024-05-06 20:48

本文主要是介绍菜鸟学Android源码-System Server服务启动(Launcher调起),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

(PS:本博客内所有源码均是Android N版本)
接上篇文章,我们转入SystemServer.java这个类中学习,该类位于/framework/base/services/java/com/android/server/

查看该类的main函数,具体代码如下:

public static void main(String[] args) {new SystemServer().run();}

从上面可以看出SystemServer.java必然实现了Runnable接口,其核心逻辑应该位于run方法中,查看run方法细节代码如下:

private void run() {try {Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitBeforeStartServices");// If a device's clock is before 1970 (before 0), a lot of// APIs crash dealing with negative numbers, notably// java.io.File#setLastModified, so instead we fake it and// hope that time from cell towers or NTP fixes it shortly.if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {Slog.w(TAG, "System clock is before 1970; setting to 1970.");SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);}// If the system has "persist.sys.language" and friends set, replace them with// "persist.sys.locale". Note that the default locale at this point is calculated// using the "-Duser.locale" command line flag. That flag is usually populated by// AndroidRuntime using the same set of system properties, but only the system_server// and system apps are allowed to set them.//// NOTE: Most changes made here will need an equivalent change to// core/jni/AndroidRuntime.cppif (!SystemProperties.get("persist.sys.language").isEmpty()) {final String languageTag = Locale.getDefault().toLanguageTag();SystemProperties.set("persist.sys.locale", languageTag);SystemProperties.set("persist.sys.language", "");SystemProperties.set("persist.sys.country", "");SystemProperties.set("persist.sys.localevar", "");}// Here we go!Slog.i(TAG, "Entered the Android system server!");EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());// In case the runtime switched since last boot (such as when// the old runtime was removed in an OTA), set the system// property so that it is in sync. We can't do this in// libnativehelper's JniInvocation::Init code where we already// had to fallback to a different runtime because it is// running as root and we need to be the system user to set// the property. http://b/11463182SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());// Enable the sampling profiler.if (SamplingProfilerIntegration.isEnabled()) {SamplingProfilerIntegration.start();mProfilerSnapshotTimer = new Timer();mProfilerSnapshotTimer.schedule(new TimerTask() {@Overridepublic void run() {SamplingProfilerIntegration.writeSnapshot("system_server", null);}}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);}// Mmmmmm... more memory!VMRuntime.getRuntime().clearGrowthLimit();// The system server has to run all of the time, so it needs to be// as efficient as possible with its memory usage.VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);// Some devices rely on runtime fingerprint generation, so make sure// we've defined it before booting further.Build.ensureFingerprintProperty();// Within the system server, it is an error to access Environment paths without// explicitly specifying a user.Environment.setUserRequired(true);// Within the system server, any incoming Bundles should be defused// to avoid throwing BadParcelableException.BaseBundle.setShouldDefuse(true);// Ensure binder calls into the system always run at foreground priority.BinderInternal.disableBackgroundScheduling(true);// Increase the number of binder threads in system_serverBinderInternal.setMaxThreads(sMaxBinderThreads);// Prepare the main looper thread (this thread).android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_FOREGROUND);android.os.Process.setCanSelfBackground(false);Looper.prepareMainLooper();// Initialize native services.System.loadLibrary("android_servers");// Check whether we failed to shut down last time we tried.// This call may not return.performPendingShutdown();// Initialize the system context.createSystemContext();// Create the system service manager.mSystemServiceManager = new SystemServiceManager(mSystemContext);LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);} finally {Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);}// Start services.try {Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");startBootstrapServices();startCoreServices();startOtherServices();} catch (Throwable ex) {Slog.e("System", "******************************************");Slog.e("System", "************ Failure starting system services", ex);throw ex;} finally {Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);}// For debug builds, log event loop stalls to dropbox for analysis.if (StrictMode.conditionallyEnableDebugLogging()) {Slog.i(TAG, "Enabled StrictMode for system server main thread.");}// Loop forever.Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}

从上面我们可以看到在设置一些系统启动的环境变量,例如说系统时间,语言,是否支持指纹等,其后进行了如下代码操作:

            startBootstrapServices();startCoreServices();startOtherServices();

从上面函数名我们就可以看出,这里开始启动系统相关的所有服务,startBootstrapServices();启动的是一些底层服务,例如PowerManagerServiceLightsServiceDisplayManagerService等系统正常运作的底层基础服务。startCoreServices();启动的是没有挂载在启动进程的服务。startOtherServices();是我们关注的重心,在这里我们要找到系统调起Launcher的过程。
startOtherService()这个函数中,我们重点关注系统准备完成后的动作,找到如下代码:

// We now tell the activity manager it is okay to run third party// code.  It will call back into us once it has gotten to the state// where third party code can really run (but before it has actually// started launching the initial applications), for us to complete our// initialization.mActivityManagerService.systemReady(new Runnable() {@Overridepublic void run() {Slog.i(TAG, "Making services ready");mSystemServiceManager.startBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PhaseActivityManagerReady");Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartObservingNativeCrashes");try {mActivityManagerService.startObservingNativeCrashes();} catch (Throwable e) {reportWtf("observing native crashes", e);}Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);if (!mOnlyCore) {Slog.i(TAG, "WebViewFactory preparation");Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WebViewFactoryPreparation");mWebViewUpdateService.prepareWebViewInSystemServer();Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);}Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartSystemUI");try {startSystemUi(context);} catch (Throwable e) {reportWtf("starting System UI", e);}Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkScoreReady");try {if (networkScoreF != null) networkScoreF.systemReady();} catch (Throwable e) {reportWtf("making Network Score Service ready", e);}Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkManagementServiceReady");try {if (networkManagementF != null) networkManagementF.systemReady();} catch (Throwable e) {reportWtf("making Network Managment Service ready", e);}Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkStatsServiceReady");try {if (networkStatsF != null) networkStatsF.systemReady();} catch (Throwable e) {reportWtf("making Network Stats Service ready", e);}Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkPolicyServiceReady");try {if (networkPolicyF != null) networkPolicyF.systemReady();} catch (Throwable e) {reportWtf("making Network Policy Service ready", e);}Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeConnectivityServiceReady");try {if (connectivityF != null) connectivityF.systemReady();} catch (Throwable e) {reportWtf("making Connectivity Service ready", e);}Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);Watchdog.getInstance().start();// It is now okay to let the various system services start their// third party code...Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PhaseThirdPartyAppsCanStart");mSystemServiceManager.startBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);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 (atlasF != null) atlasF.systemRunning();} catch (Throwable e) {reportWtf("Notifying AssetAtlasService running", e);}try {// TODO(BT) Pass parameter to input managerif (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);}try {if (mmsServiceF != null) mmsServiceF.systemRunning();} catch (Throwable e) {reportWtf("Notifying MmsService running", e);}try {if (networkScoreF != null) networkScoreF.systemRunning();} catch (Throwable e) {reportWtf("Notifying NetworkScoreService running", e);}Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);}});

从注释我们可以看出,在这里会进行调起Launcher的动作,点击进入SystemReady这个函数的细节,从而进入了ActivityManagerService.java,该类位于/framework/base/services/core/java/com/android/server/am/下,完整的systemReady函数代码如下:

public void systemReady(final Runnable goingCallback) {synchronized(this) {if (mSystemReady) {// If we're done calling all the receivers, run the next "boot phase" passed in// by the SystemServerif (goingCallback != null) {goingCallback.run();}return;}mLocalDeviceIdleController= LocalServices.getService(DeviceIdleController.LocalService.class);// 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);Slog.i(TAG, "Removing system update proc: " + proc);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;}Slog.i(TAG, "System now ready");EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,SystemClock.uptimeMillis());synchronized(this) {// Make sure we have no pre-ready processes sitting around.if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {ResolveInfo ri = mContext.getPackageManager().resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),STOCK_PM_FLAGS);CharSequence errorMsg = null;if (ri != null) {ActivityInfo ai = ri.activityInfo;ApplicationInfo app = ai.applicationInfo;if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {mTopAction = Intent.ACTION_FACTORY_TEST;mTopData = null;mTopComponent = new ComponentName(app.packageName,ai.name);} else {errorMsg = mContext.getResources().getText(com.android.internal.R.string.factorytest_not_system);}} else {errorMsg = mContext.getResources().getText(com.android.internal.R.string.factorytest_no_action);}if (errorMsg != null) {mTopAction = null;mTopData = null;mTopComponent = null;Message msg = Message.obtain();msg.what = SHOW_FACTORY_ERROR_UI_MSG;msg.getData().putCharSequence("msg", errorMsg);mUiHandler.sendMessage(msg);}}}retrieveSettings();final int currentUserId;synchronized (this) {currentUserId = mUserController.getCurrentUserIdLocked();readGrantedUriPermissionsLocked();}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);mSystemServiceManager.startUser(currentUserId);synchronized (this) {// Only start up encryption-aware persistent apps; once user is// unlocked we'll come back around and start unaware appsstartPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);// Start up initial activity.mBooting = true;// Enable home activity for system user, so that the system can always bootif (UserManager.isSplitSystemUser()) {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();}}startHomeActivityLocked(currentUserId, "systemReady");try {if (AppGlobals.getPackageManager().hasSystemUidErrors()) {Slog.e(TAG, "UIDs on the system are inconsistent, you need to wipe your"+ " data partition or your device will be unstable.");mUiHandler.obtainMessage(SHOW_UID_ERROR_UI_MSG).sendToTarget();}} catch (RemoteException e) {}if (!Build.isBuildConsistent()) {Slog.e(TAG, "Build fingerprint is not consistent, warning user");mUiHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_UI_MSG).sendToTarget();}long ident = Binder.clearCallingIdentity();try {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, AppOpsManager.OP_NONE,null, false, false, MY_PID, Process.SYSTEM_UID,currentUserId);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() {@Overridepublic 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}, AppOpsManager.OP_NONE,null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);} catch (Throwable t) {Slog.wtf(TAG, "Failed sending first user broadcasts", t);} finally {Binder.restoreCallingIdentity(ident);}mStackSupervisor.resumeFocusedStackTopActivityLocked();mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);}}

从上面我们可以看出,在这部分代码完成后,会回调传入的Runnable接口,仔细察看这段代码,我们看到startHomeActivityLocked(currentUserId, "systemReady");这样一个函数,从函数名可以看出,在这里其调起了系统的Launcher,跳入函数内部,查看代码细节:

boolean startHomeActivityLocked(int userId, String reason) {if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL&& mTopAction == null) {// We are running in factory test mode, but unable to find// the factory test app, so just sit around displaying the// error message and don't try to start anything.return false;}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.instrumentationClass == null) {intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);}} else {Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());}return true;}
boolean startHomeActivityLocked(int userId, String reason) {if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL&& mTopAction == null) {// We are running in factory test mode, but unable to find// the factory test app, so just sit around displaying the// error message and don't try to start anything.return false;}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.instrumentationClass == null) {intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);}} else {Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());}return true;}
Intent getHomeIntent() {Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);intent.setComponent(mTopComponent);intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {intent.addCategory(Intent.CATEGORY_HOME);}return intent;}

从上面这三个函数,我们可以看出其最终是走入同路径下的ActivityStarter.java,以Intent的形式调起了系统默认的Launcher应用。

最新文章更新在微信公众号上,欢迎关注获取详情:
这里写图片描述

这篇关于菜鸟学Android源码-System Server服务启动(Launcher调起)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/965342

相关文章

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

springboot3打包成war包,用tomcat8启动

1、在pom中,将打包类型改为war <packaging>war</packaging> 2、pom中排除SpringBoot内置的Tomcat容器并添加Tomcat依赖,用于编译和测试,         *依赖时一定设置 scope 为 provided (相当于 tomcat 依赖只在本地运行和测试的时候有效,         打包的时候会排除这个依赖)<scope>provided

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹,比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”,打开命令提示符,进入到发布代码目录 命令行启动.netcore项目的命令为:  dotnet 项目启动文件.dll --urls="http://*:对外端口" --ip="本机ip" --port=项目内部端口 例: dotnet Imagine.M