System Server是Android系统的核心,他在Dalvik虚拟机启动后立即开始初始化和运行。其它的系统服务在System Server进程的环境中运行。/base/services/java/com/android/server/SystemServer.java

Java代码
  1. /**
  2. *ThismethodiscalledfromZygotetoinitializethesystem.Thiswillcausethenative
  3. *services(SurfaceFlinger,AudioFlinger,etc..)tobestarted.Afterthatitwillcallback
  4. *upintoinit2()tostarttheAndroidservices.
  5. */
  6. native public static void init1(String[]args);
  7. public static void main(String[]args){
  8. if (System.currentTimeMillis()<EARLIEST_SUPPORTED_TIME){
  9. //Ifadevice'sclockisbefore1970(before0),alotof
  10. //APIscrashdealingwithnegativenumbers,notably
  11. //java.io.File#setLastModified,soinsteadwefakeitand
  12. //hopethattimefromcelltowersorNTPfixesit
  13. //shortly.
  14. Slog.w(TAG,"Systemclockisbefore1970;settingto1970." );
  15. SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
  16. }
  17. if (SamplingProfilerIntegration.isEnabled()){
  18. SamplingProfilerIntegration.start();
  19. timer=new Timer();
  20. timer.schedule(new TimerTask(){
  21. @Override
  22. public void run(){
  23. SamplingProfilerIntegration.writeSnapshot("system_server" );
  24. }
  25. },SNAPSHOT_INTERVAL,SNAPSHOT_INTERVAL);
  26. }
  27. //Thesystemserverhastorunallofthetime,soitneedstobe
  28. //asefficientaspossiblewithitsmemoryusage.
  29. VMRuntime.getRuntime().setTargetHeapUtilization(0 .8f);
  30. System.loadLibrary("android_servers" );
  31. init1(args);
  32. }
  33. public static final void init2(){
  34. Slog.i(TAG,"EnteredtheAndroidsystemserver!" );
  35. Threadthr=new ServerThread();
  36. thr.setName("android.server.ServerThread" );
  37. thr.start();
  38. }

在main函数中,首先检查系统时间设置和SamplingProfiler。然后加载一个叫android_servers的本地库,他提供本 地方法的接口(源程序在framework/base/services/jni/目录中)。然后调用本地方法设置服务。具体执行设置的代码在 frameworks/base/cmds/system_server/library/system_init.cpp中。

C代码
  1. extern "C" status_tsystem_init()
  2. {
  3. LOGI("Enteredsystem_init()" );
  4. sp<ProcessState>proc(ProcessState::self());
  5. sp<IServiceManager>sm=defaultServiceManager();
  6. LOGI("ServiceManager:%p\n" ,sm.get());
  7. sp<GrimReaper>grim=new GrimReaper();
  8. sm->asBinder()->linkToDeath(grim,grim.get(),0);
  9. char propBuf[PROPERTY_VALUE_MAX];
  10. property_get("system_init.startsurfaceflinger" ,propBuf, "1" );
  11. if (strcmp(propBuf, "1" )==0){
  12. //StarttheSurfaceFlinger
  13. SurfaceFlinger::instantiate();
  14. }
  15. //Startthesensorservice
  16. SensorService::instantiate();
  17. //Onthesimulator,audioflingeretaldon'tgetstartedthe
  18. //samewayasonthedevice,andweneedtostartthemhere
  19. if (!proc->supportsProcesses()){
  20. //StarttheAudioFlinger
  21. AudioFlinger::instantiate();
  22. //Startthemediaplaybackservice
  23. MediaPlayerService::instantiate();
  24. //Startthecameraservice
  25. CameraService::instantiate();
  26. //Starttheaudiopolicyservice
  27. AudioPolicyService::instantiate();
  28. }
  29. //AndnowstarttheAndroidruntime.Wehavetodothisbit
  30. //ofnastinessbecausetheAndroidruntimeinitializationrequires
  31. //someofthecoresystemservicestoalreadybestarted.
  32. //AllotherserversshouldjuststarttheAndroidruntimeat
  33. //thebeginningoftheirprocesses'smain(),beforecalling
  34. //theinitfunction.
  35. LOGI("Systemserver:startingAndroidruntime.\n" );
  36. AndroidRuntime*runtime=AndroidRuntime::getRuntime();
  37. LOGI("Systemserver:startingAndroidservices.\n" );
  38. runtime->callStatic("com/android/server/SystemServer" , "init2" );
  39. //Ifrunninginourownprocess,justgointothethread
  40. //pool.Otherwise,calltheinitializationfinished
  41. //functoletthisprocesscontinueitsinitilization.
  42. if (proc->supportsProcesses()){
  43. LOGI("Systemserver:enteringthreadpool.\n" );
  44. ProcessState::self()->startThreadPool();
  45. IPCThreadState::self()->joinThreadPool();
  46. LOGI("Systemserver:exitingthreadpool.\n" );
  47. }
  48. return NO_ERROR;
  49. }

等初始化传感器,视频,音频等服务后,调用一个回调方法init2 (在SystemServer.java中)。在上面的代码可以看到,这个方法开启了ServerThread来初始化其它的服务。

Java代码
  1. public void run(){
  2. EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,
  3. SystemClock.uptimeMillis());
  4. Looper.prepare();
  5. android.os.Process.setThreadPriority(
  6. android.os.Process.THREAD_PRIORITY_FOREGROUND);
  7. BinderInternal.disableBackgroundScheduling(true );
  8. android.os.Process.setCanSelfBackground(false );
  9. //Checkwhetherwefailedtoshutdownlasttimewetried.
  10. {
  11. final StringshutdownAction=SystemProperties.get(
  12. ShutdownThread.SHUTDOWN_ACTION_PROPERTY,"" );
  13. if (shutdownAction!= null &&shutdownAction.length()> 0 ){
  14. boolean reboot=(shutdownAction.charAt( 0 )== '1' );
  15. final Stringreason;
  16. if (shutdownAction.length()> 1 ){
  17. reason=shutdownAction.substring(1 ,shutdownAction.length());
  18. }else {
  19. reason=null ;
  20. }
  21. ShutdownThread.rebootOrShutdown(reboot,reason);
  22. }
  23. }
  24. StringfactoryTestStr=SystemProperties.get("ro.factorytest" );
  25. int factoryTest= "" .equals(factoryTestStr)?SystemServer.FACTORY_TEST_OFF
  26. :Integer.parseInt(factoryTestStr);
  27. LightsServicelights=null ;
  28. PowerManagerServicepower=null ;
  29. BatteryServicebattery=null ;
  30. ConnectivityServiceconnectivity=null ;
  31. IPackageManagerpm=null ;
  32. Contextcontext=null ;
  33. WindowManagerServicewm=null ;
  34. BluetoothServicebluetooth=null ;
  35. BluetoothA2dpServicebluetoothA2dp=null ;
  36. HeadsetObserverheadset=null ;
  37. DockObserverdock=null ;
  38. UsbServiceusb=null ;
  39. UiModeManagerServiceuiMode=null ;
  40. RecognitionManagerServicerecognition=null ;
  41. ThrottleServicethrottle=null ;
  42. //Criticalservices...
  43. try {
  44. Slog.i(TAG,"EntropyService" );
  45. ServiceManager.addService("entropy" , new EntropyService());
  46. Slog.i(TAG,"PowerManager" );
  47. power=new PowerManagerService();
  48. ServiceManager.addService(Context.POWER_SERVICE,power);
  49. Slog.i(TAG,"ActivityManager" );
  50. context=ActivityManagerService.main(factoryTest);
  51. Slog.i(TAG,"TelephonyRegistry" );
  52. ServiceManager.addService("telephony.registry" , new TelephonyRegistry(context));
  53. AttributeCache.init(context);
  54. Slog.i(TAG,"PackageManager" );
  55. pm=PackageManagerService.main(context,
  56. factoryTest!=SystemServer.FACTORY_TEST_OFF);
  57. ActivityManagerService.setSystemProcess();
  58. mContentResolver=context.getContentResolver();
  59. //TheAccountManagermustcomebeforetheContentService
  60. try {
  61. Slog.i(TAG,"AccountManager" );
  62. ServiceManager.addService(Context.ACCOUNT_SERVICE,
  63. new AccountManagerService(context));
  64. }catch (Throwablee){
  65. Slog.e(TAG,"FailurestartingAccountManager" ,e);
  66. }
  67. Slog.i(TAG,"ContentManager" );
  68. ContentService.main(context,
  69. factoryTest==SystemServer.FACTORY_TEST_LOW_LEVEL);
  70. Slog.i(TAG,"SystemContentProviders" );
  71. ActivityManagerService.installSystemProviders();
  72. Slog.i(TAG,"BatteryService" );
  73. battery=new BatteryService(context);
  74. ServiceManager.addService("battery" ,battery);
  75. Slog.i(TAG,"LightsService" );
  76. lights=new LightsService(context);
  77. Slog.i(TAG,"VibratorService" );
  78. ServiceManager.addService("vibrator" , new VibratorService(context));
  79. //onlyinitializethepowerserviceafterwehavestartedthe
  80. //lightsservice,contentprovidersandthebatteryservice.
  81. power.init(context,lights,ActivityManagerService.getDefault(),battery);
  82. Slog.i(TAG,"AlarmManager" );
  83. AlarmManagerServicealarm=new AlarmManagerService(context);
  84. ServiceManager.addService(Context.ALARM_SERVICE,alarm);
  85. Slog.i(TAG,"InitWatchdog" );
  86. Watchdog.getInstance().init(context,battery,power,alarm,
  87. ActivityManagerService.self());
  88. Slog.i(TAG,"WindowManager" );
  89. wm=WindowManagerService.main(context,power,
  90. factoryTest!=SystemServer.FACTORY_TEST_LOW_LEVEL);
  91. ServiceManager.addService(Context.WINDOW_SERVICE,wm);
  92. ((ActivityManagerService)ServiceManager.getService("activity" ))
  93. .setWindowManager(wm);
  94. //SkipBluetoothifwehaveanemulatorkernel
  95. //TODO:Useamorereliablechecktoseeifthisproductshould
  96. //supportBluetooth-seebug988521
  97. if (SystemProperties.get( "ro.kernel.qemu" ).equals( "1" )){
  98. Slog.i(TAG,"RegisteringnullBluetoothService(emulator)" );
  99. ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE,null );
  100. }else if (factoryTest==SystemServer.FACTORY_TEST_LOW_LEVEL){
  101. Slog.i(TAG,"RegisteringnullBluetoothService(factorytest)" );
  102. ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE,null );
  103. }else {
  104. Slog.i(TAG,"BluetoothService" );
  105. bluetooth=new BluetoothService(context);
  106. ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE,bluetooth);
  107. bluetooth.initAfterRegistration();
  108. bluetoothA2dp=new BluetoothA2dpService(context,bluetooth);
  109. ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
  110. bluetoothA2dp);
  111. int bluetoothOn=Settings.Secure.getInt(mContentResolver,
  112. Settings.Secure.BLUETOOTH_ON,0 );
  113. if (bluetoothOn> 0 ){
  114. bluetooth.enable();
  115. }
  116. }
  117. }catch (RuntimeExceptione){
  118. Slog.e("System" , "Failurestartingcoreservice" ,e);
  119. }
  120. DevicePolicyManagerServicedevicePolicy=null ;
  121. StatusBarManagerServicestatusBar=null ;
  122. InputMethodManagerServiceimm=null ;
  123. AppWidgetServiceappWidget=null ;
  124. NotificationManagerServicenotification=null ;
  125. WallpaperManagerServicewallpaper=null ;
  126. LocationManagerServicelocation=null ;
  127. if (factoryTest!=SystemServer.FACTORY_TEST_LOW_LEVEL){
  128. try {
  129. Slog.i(TAG,"DevicePolicy" );
  130. devicePolicy=new DevicePolicyManagerService(context);
  131. ServiceManager.addService(Context.DEVICE_POLICY_SERVICE,devicePolicy);
  132. }catch (Throwablee){
  133. Slog.e(TAG,"FailurestartingDevicePolicyService" ,e);
  134. }
  135. try {
  136. Slog.i(TAG,"StatusBar" );
  137. statusBar=new StatusBarManagerService(context);
  138. ServiceManager.addService(Context.STATUS_BAR_SERVICE,statusBar);
  139. }catch (Throwablee){
  140. Slog.e(TAG,"FailurestartingStatusBarManagerService" ,e);
  141. }
  142. try {
  143. Slog.i(TAG,"ClipboardService" );
  144. ServiceManager.addService(Context.CLIPBOARD_SERVICE,
  145. new ClipboardService(context));
  146. }catch (Throwablee){
  147. Slog.e(TAG,"FailurestartingClipboardService" ,e);
  148. }
  149. try {
  150. Slog.i(TAG,"InputMethodService" );
  151. imm=new InputMethodManagerService(context,statusBar);
  152. ServiceManager.addService(Context.INPUT_METHOD_SERVICE,imm);
  153. }catch (Throwablee){
  154. Slog.e(TAG,"FailurestartingInputManagerService" ,e);
  155. }
  156. try {
  157. Slog.i(TAG,"NetStatService" );
  158. ServiceManager.addService("netstat" , new NetStatService(context));
  159. }catch (Throwablee){
  160. Slog.e(TAG,"FailurestartingNetStatService" ,e);
  161. }
  162. try {
  163. Slog.i(TAG,"NetworkManagementService" );
  164. ServiceManager.addService(
  165. Context.NETWORKMANAGEMENT_SERVICE,
  166. NetworkManagementService.create(context));
  167. }catch (Throwablee){
  168. Slog.e(TAG,"FailurestartingNetworkManagementService" ,e);
  169. }
  170. try {
  171. Slog.i(TAG,"ConnectivityService" );
  172. connectivity=ConnectivityService.getInstance(context);
  173. ServiceManager.addService(Context.CONNECTIVITY_SERVICE,connectivity);
  174. }catch (Throwablee){
  175. Slog.e(TAG,"FailurestartingConnectivityService" ,e);
  176. }
  177. try {
  178. Slog.i(TAG,"ThrottleService" );
  179. throttle=new ThrottleService(context);
  180. ServiceManager.addService(
  181. Context.THROTTLE_SERVICE,throttle);
  182. }catch (Throwablee){
  183. Slog.e(TAG,"FailurestartingThrottleService" ,e);
  184. }
  185. try {
  186. Slog.i(TAG,"AccessibilityManager" );
  187. ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
  188. new AccessibilityManagerService(context));
  189. }catch (Throwablee){
  190. Slog.e(TAG,"FailurestartingAccessibilityManager" ,e);
  191. }
  192. try {
  193. /*
  194. *NotificationManagerServiceisdependantonMountService,
  195. *(formedia/usbnotifications)sowemuststartMountServicefirst.
  196. */
  197. Slog.i(TAG,"MountService" );
  198. ServiceManager.addService("mount" , new MountService(context));
  199. }catch (Throwablee){
  200. Slog.e(TAG,"FailurestartingMountService" ,e);
  201. }
  202. try {
  203. Slog.i(TAG,"NotificationManager" );
  204. notification=new NotificationManagerService(context,statusBar,lights);
  205. ServiceManager.addService(Context.NOTIFICATION_SERVICE,notification);
  206. }catch (Throwablee){
  207. Slog.e(TAG,"FailurestartingNotificationManager" ,e);
  208. }
  209. try {
  210. Slog.i(TAG,"DeviceStorageMonitor" );
  211. ServiceManager.addService(DeviceStorageMonitorService.SERVICE,
  212. new DeviceStorageMonitorService(context));
  213. }catch (Throwablee){
  214. Slog.e(TAG,"FailurestartingDeviceStorageMonitorservice" ,e);
  215. }
  216. try {
  217. Slog.i(TAG,"LocationManager" );
  218. location=new LocationManagerService(context);
  219. ServiceManager.addService(Context.LOCATION_SERVICE,location);
  220. }catch (Throwablee){
  221. Slog.e(TAG,"FailurestartingLocationManager" ,e);
  222. }
  223. try {
  224. Slog.i(TAG,"SearchService" );
  225. ServiceManager.addService(Context.SEARCH_SERVICE,
  226. new SearchManagerService(context));
  227. }catch (Throwablee){
  228. Slog.e(TAG,"FailurestartingSearchService" ,e);
  229. }
  230. if (INCLUDE_DEMO){
  231. Slog.i(TAG,"Installingdemodata..." );
  232. (new DemoThread(context)).start();
  233. }
  234. try {
  235. Slog.i(TAG,"DropBoxService" );
  236. ServiceManager.addService(Context.DROPBOX_SERVICE,
  237. new DropBoxManagerService(context, new File( "/data/system/dropbox" )));
  238. }catch (Throwablee){
  239. Slog.e(TAG,"FailurestartingDropBoxManagerService" ,e);
  240. }
  241. try {
  242. Slog.i(TAG,"WallpaperService" );
  243. wallpaper=new WallpaperManagerService(context);
  244. ServiceManager.addService(Context.WALLPAPER_SERVICE,wallpaper);
  245. }catch (Throwablee){
  246. Slog.e(TAG,"FailurestartingWallpaperService" ,e);
  247. }
  248. try {
  249. Slog.i(TAG,"AudioService" );
  250. ServiceManager.addService(Context.AUDIO_SERVICE,new AudioService(context));
  251. }catch (Throwablee){
  252. Slog.e(TAG,"FailurestartingAudioService" ,e);
  253. }
  254. try {
  255. Slog.i(TAG,"HeadsetObserver" );
  256. //Listenforwiredheadsetchanges
  257. headset=new HeadsetObserver(context);
  258. }catch (Throwablee){
  259. Slog.e(TAG,"FailurestartingHeadsetObserver" ,e);
  260. }
  261. try {
  262. Slog.i(TAG,"DockObserver" );
  263. //Listenfordockstationchanges
  264. dock=new DockObserver(context,power);
  265. }catch (Throwablee){
  266. Slog.e(TAG,"FailurestartingDockObserver" ,e);
  267. }
  268. try {
  269. Slog.i(TAG,"USBService" );
  270. //ListenforUSBchanges
  271. usb=new UsbService(context);
  272. ServiceManager.addService(Context.USB_SERVICE,usb);
  273. }catch (Throwablee){
  274. Slog.e(TAG,"FailurestartingUsbService" ,e);
  275. }
  276. try {
  277. Slog.i(TAG,"UIModeManagerService" );
  278. //ListenforUImodechanges
  279. uiMode=new UiModeManagerService(context);
  280. }catch (Throwablee){
  281. Slog.e(TAG,"FailurestartingUiModeManagerService" ,e);
  282. }
  283. try {
  284. Slog.i(TAG,"BackupService" );
  285. ServiceManager.addService(Context.BACKUP_SERVICE,
  286. new BackupManagerService(context));
  287. }catch (Throwablee){
  288. Slog.e(TAG,"FailurestartingBackupService" ,e);
  289. }
  290. try {
  291. Slog.i(TAG,"AppWidgetService" );
  292. appWidget=new AppWidgetService(context);
  293. ServiceManager.addService(Context.APPWIDGET_SERVICE,appWidget);
  294. }catch (Throwablee){
  295. Slog.e(TAG,"FailurestartingAppWidgetService" ,e);
  296. }
  297. try {
  298. Slog.i(TAG,"RecognitionService" );
  299. recognition=new RecognitionManagerService(context);
  300. }catch (Throwablee){
  301. Slog.e(TAG,"FailurestartingRecognitionService" ,e);
  302. }
  303. try {
  304. Slog.i(TAG,"DiskStatsService" );
  305. ServiceManager.addService("diskstats" , new DiskStatsService(context));
  306. }catch (Throwablee){
  307. Slog.e(TAG,"FailurestartingDiskStatsService" ,e);
  308. }
  309. }
  310. //makesuretheADB_ENABLEDsettingvaluematchesthesecurepropertyvalue
  311. Settings.Secure.putInt(mContentResolver,Settings.Secure.ADB_ENABLED,
  312. "1" .equals(SystemProperties.get( "persist.service.adb.enable" ))? 1 : 0 );
  313. //registerobservertolistenforsettingschanges
  314. mContentResolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
  315. false , new AdbSettingsObserver());
  316. //Beforethingsstartrolling,besurewehavedecidedwhether
  317. //weareinsafemode.
  318. final boolean safeMode=wm.detectSafeMode();
  319. if (safeMode){
  320. try {
  321. ActivityManagerNative.getDefault().enterSafeMode();
  322. //PostthesafemodestateintheZygoteclass
  323. Zygote.systemInSafeMode=true ;
  324. //DisabletheJITforthesystem_serverprocess
  325. VMRuntime.getRuntime().disableJitCompilation();
  326. }catch (RemoteExceptione){
  327. }
  328. }else {
  329. //EnabletheJITforthesystem_serverprocess
  330. VMRuntime.getRuntime().startJitCompilation();
  331. }
  332. //Itisnowtimetostartuptheappprocesses...
  333. if (devicePolicy!= null ){
  334. devicePolicy.systemReady();
  335. }
  336. if (notification!= null ){
  337. notification.systemReady();
  338. }
  339. if (statusBar!= null ){
  340. statusBar.systemReady();
  341. }
  342. wm.systemReady();
  343. power.systemReady();
  344. try {
  345. pm.systemReady();
  346. }catch (RemoteExceptione){
  347. }
  348. //Theseareneededtopropagatetotherunnablebelow.
  349. final StatusBarManagerServicestatusBarF=statusBar;
  350. final BatteryServicebatteryF=battery;
  351. final ConnectivityServiceconnectivityF=connectivity;
  352. final DockObserverdockF=dock;
  353. final UsbServiceusbF=usb;
  354. final ThrottleServicethrottleF=throttle;
  355. final UiModeManagerServiceuiModeF=uiMode;
  356. final AppWidgetServiceappWidgetF=appWidget;
  357. final WallpaperManagerServicewallpaperF=wallpaper;
  358. final InputMethodManagerServiceimmF=imm;
  359. final RecognitionManagerServicerecognitionF=recognition;
  360. final LocationManagerServicelocationF=location;
  361. //Wenowtelltheactivitymanageritisokaytorunthirdparty
  362. //code.Itwillcallbackintousonceithasgottentothestate
  363. //wherethirdpartycodecanreallyrun(butbeforeithasactually
  364. //startedlaunchingtheinitialapplications),forustocompleteour
  365. //initialization.
  366. ((ActivityManagerService)ActivityManagerNative.getDefault())
  367. .systemReady(new Runnable(){
  368. public void run(){
  369. Slog.i(TAG,"Makingservicesready" );
  370. if (statusBarF!= null )statusBarF.systemReady2();
  371. if (batteryF!= null )batteryF.systemReady();
  372. if (connectivityF!= null )connectivityF.systemReady();
  373. if (dockF!= null )dockF.systemReady();
  374. if (usbF!= null )usbF.systemReady();
  375. if (uiModeF!= null )uiModeF.systemReady();
  376. if (recognitionF!= null )recognitionF.systemReady();
  377. Watchdog.getInstance().start();
  378. //Itisnowokaytoletthevarioussystemservicesstarttheir
  379. //thirdpartycode...
  380. if (appWidgetF!= null )appWidgetF.systemReady(safeMode);
  381. if (wallpaperF!= null )wallpaperF.systemReady();
  382. if (immF!= null )immF.systemReady();
  383. if (locationF!= null )locationF.systemReady();
  384. if (throttleF!= null )throttleF.systemReady();
  385. }
  386. });
  387. //Fordebugbuilds,logeventloopstallstodropboxforanalysis.
  388. if (StrictMode.conditionallyEnableDebugLogging()){
  389. Slog.i(TAG,"EnabledStrictModeforsystemservermainthread." );
  390. }
  391. Looper.loop();
  392. Slog.d(TAG,"SystemServerThreadisexiting!" );
  393. }

这里启动的没一个进程都作为一个Dalvik线程而存在于SystemServer进程里面。





更多相关文章

  1. Android软键盘挡住输入框的问题及解决方法
  2. android全屏去掉title栏的多种实现方法
  3. Android(安卓)前置摄像头的默认是180度,导致应用拍照和录制视频是
  4. Android(安卓)GestureDetector方法详解
  5. android edittext不弹出软键盘
  6. android:屏幕自适应
  7. Android与H5互调
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. 【决战西二旗】|理解Sort算法
  2. COVID-19每日据整理|04-01
  3. Python告诉你想开一家美食店该怎么做
  4. 技术解析|如何绘制密度分布图
  5. 动画:面试算法之重建二叉树
  6. 不能再简单了|手把手教你爬取美国疫情实时
  7. 一次爬美团网美食团购的经历
  8. 那些年,我在大学接过的外包项目
  9. JDBC自定义工具类(properties配置文件方式
  10. COVID-19每日据整理|04-02