- 浏览: 208159 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
xumin_minzi:
我也在使用ndk编译,ffmpeg源码放在哪个目录里面?
[原创]Android ndkr8编译 FFmpeg 0.11.1 "Happiness" -
ericchan2012:
在Dialog调用show方法之后
【原创】Android 设置Dialog的长宽和位置 -
maohualei:
求解: 我设置的时候 位置居然没有反应 dial ...
【原创】Android 设置Dialog的长宽和位置
参考了网上的资料和源码,肤浅分析了下,不够深入。
Android APK安装原理分析
一、概述
APK是Android Package的缩写,即Android安装包。
APK安装可以通过以下四种方式:
1. 系统应用安装,开机时完成系统应用的检查,没安装就安装,安装就跳过,无安装界面。
2. 网络下载应用安装,通过market应用完成,无安装界面。
3. ADB工具安装,无安装界面
4. 通过SD卡来安装apk,有安装界面,由packageinstaller.apk应用处理安装及卸载过程的界面。
应用安装涉及到如下几个目录:
system/app 系统自带的应用程序,无法删除
data/app 用户程序安装的目录,有删除权限
data/data 存放应用程序的数据
Data/dalvik-cache 将apk中的dex文件安装到dalvik-cache目录下
(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一)
二、系统应用安装
PackageManagerService处理各种应用的安装,卸载,管理等工作,系统启动时由systemServer开启此服务。
@ frameworks/base/services/java/com/android/server/SystemServer.java
...
Slog.i(TAG, "Package Manager");
pm = PackageManagerService.main(context, factoryTest != SystemServer.FACTORY_TEST_OFF);
...
@ frameworks/base/services/java/com/android/server/PackageManagerService.java
public static final IPackageManager main(Context context, boolean factoryTest) {
PackageManagerService m = new PackageManagerService(context, factoryTest);
ServiceManager.addService("package", m); // 将PackageManagerService添加到ServiceManager中。
return m;
}
上面new一个PackageManagerService出来,当然首先调用的函数是他的构造函数了,那么系统应用都是在这个函数中完成安装的。
public PackageManagerService(Context context, boolean factoryTest) {
...
addBootEvent(new String("Android:PackageManagerService_Start"));
mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
...
Installer installer = new Installer();
// 这个Installer类其实是利用socket和installd(c语言)通讯来实现安装,关于installd的实现另外分析。
if (installer.ping() && Process.supportsProcesses()) {
mInstaller = installer;
} else {
mInstaller = null;
}
...
File dataDir = Environment.getDataDirectory();
mAppDataDir = new File(dataDir, "data"); // /data/data
mSecureAppDataDir = new File(dataDir, "secure/data"); // /data/secure/data
mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); // /data/app-private
...
long startTime = SystemClock.uptimeMillis();
addBootEvent(new String("Android:PMS_scan_START"));
...
int scanMode = SCAN_MONITOR | SCAN_NO_PATHS;
if (mNoDexOpt) {
Slog.w(TAG, "Running ENG build: no pre-dexopt!");
scanMode |= SCAN_NO_DEX;
}
...
mFrameworkDir = new File(Environment.getRootDirectory(), "framework"); // /system/framework
mDalvikCacheDir = new File(dataDir, "dalvik-cache"); // /data/dalvik-cache
// 对apk中的DEX文件进行安装时优化,优化之后的ODEX文件存放在/data/dalvik-cache。
...
// 类PackageManagerService的内部类AppDirObserver实现了监听某个目录的功能,当把某个apk或者jar包放入被监听的目录,
将会被自动安装。
mFrameworkInstallObserver = new AppDirObserver(mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
// 新建一个目录监听的对象
mFrameworkInstallObserver.startWatching(); // 开始监听这个目录
scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR,
scanMode | SCAN_NO_DEX, 0); // 扫描安装“system\framework”目录下的jar包。
addBootEvent(new String("Android:PMS_scan_done:" + mFrameworkDir.getPath().toString()));
// 扫描安装“system\app”目录下的各个系统应用。
mSystemAppDir = new File(Environment.getRootDirectory(), "app");
mSystemInstallObserver = new AppDirObserver(mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
mSystemInstallObserver.startWatching();
scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
addBootEvent(new String("Android:PMS_scan_done:" + mSystemAppDir.getPath().toString()));
// 扫描安装"/vendor/app"下的各应用, 源码和上面类似
...
addBootEvent(new String("Android:PMS_scan_done:" + mVendorAppDir.getPath().toString()));
// Prune删除 any system packages that no longer exist.
...
mAppInstallDir = new File(dataDir, "app");
addBootEvent(new String("Android:PMS_scan_data_start"));
mAppInstallObserver = new AppDirObserver(mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
mAppInstallObserver.startWatching();
scanDirLI(mAppInstallDir, 0, scanMode, 0); // 扫描安装/data/app下面的应用。
addBootEvent(new String("Android:PMS_scan_data_done:" + mAppInstallDir.getPath().toString()));
// 扫描安装" data\app-private"目录,即安装DRM保护的APK文件。
mDrmAppInstallObserver = new AppDirObserver(mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
mDrmAppInstallObserver.startWatching();
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode, 0);
addBootEvent(new String("Android:PMS_scan_data_done:" + mDrmAppPrivateInstallDir.getPath().toString()));
...
addBootEvent(new String("Android:PMS_scan_END"));
Slog.i(TAG, "Time to scan packages: " + ((SystemClock.uptimeMillis()-startTime)/1000f) + " seconds");
...
}
以上可以看出,主要的工作是由函数scanDirLI()来完成的。
private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
String[] files = dir.list();
if (files == null) {
Log.d(TAG, "No files in app dir " + dir);
return;
}
if (false) {
Log.d(TAG, "Scanning app dir " + dir);
}
int i;
for (i=0; i<files.length; i++) {
File file = new File(dir, files[i]);// 构造apk的全路径名字
if (!isPackageFilename(files[i])) {// 检查是否是以.apk结尾的文件,不是就跳过。
// Ignore entries which are not apk's
continue;
}
//安装apk文件,安装包解析器
PackageParser.Package pkg = scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);
// Don't mess around with apps in system partition.
if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
// Delete the apk
Slog.w(TAG, "Cleaning up failed install of " + file);
file.delete();
}
}
}
scanPackageLI函数扫描一个package,同时返回一个新解析出来的包。
private PackageParser.Package scanPackageLI(File scanFile,
int parseFlags, int scanMode, long currentTime) {
...
final PackageParser.Package pkg = pp.parsePackage(scanFile,
scanPath, mMetrics, parseFlags);
...
codePath = pkg.mScanPath;
// Set application objects path explicitly.
setApplicationInfoPaths(pkg, codePath, resPath);
// 通过解析安装包parsePackage获取到安装包的信息结构。
return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime);
}
private static void setApplicationInfoPaths(PackageParser.Package pkg, String destCodePath,
String destResPath) {
pkg.mPath = pkg.mScanPath = destCodePath;
pkg.applicationInfo.sourceDir = destCodePath;
pkg.applicationInfo.publicSourceDir = destResPath;
}
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, long currentTime) {
File scanFile = new File(pkg.mScanPath);
// Protect for GMS2.2 NetworkLocation.apk will cause system can't boot normally
// on Android 2.3 above
if(pkg.packageName.equalsIgnoreCase("com.google.android.location")
&& (mSdkVersion >= 9) && (pkg.applicationInfo.targetSdkVersion <=){
Slog.w(TAG, "Target SDK version: " + mSdkVersion);
Slog.w(TAG, "Application SDK version: " + pkg.applicationInfo.targetSdkVersion);
Slog.w(TAG, "App SDK version is incompatible with Target SDK version, install failed.");
return null;
}
...
// Initialize package source and resource directories
...
// Check all shared libraries and map to their actual file path.
...
// Check if we are renaming from an original package name.
...
...
...
//最后会通过下面这个函数来实现真正的安装。
File dataPath;
if (mPlatformPackage == pkg) {
...
} else {
// This is a normal package, need to make its data directory.
boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(pkg);
dataPath = getDataPathForPackage(pkg);
if (dataPath.exists()) {
...
mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid, pkg.applicationInfo.uid);
...
} else {
...
int ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid,
pkg.applicationInfo.uid);
...
}
...
}
Installer类的实现位于文件: frameworks/base/services/java/com/android/server/Installer.java
该类实现的只是一个接口,使用socket来和c代码实现的installd进行通信,实际真正完成安装任务的installd服务
其源码位于:frameworks/base/cmds/installd
这部分在另外一篇文章中分析。
三、从Market上下载应用
Google Market应用需要使用gmail账户登录才可以使用,选择某一应用后,开始下载安装包,此过程中,在手机通知栏有进度条提示,下载完成后,会自动调用Packagemanager的接口安装,调用接口如下:
public void installPackage(final Uri packageURI, final IPackageInstallObserver observer, final int flags)
final Uri packageURI:文件下载完成后保存的路径
final IPackageInstallObserver observer:返回的安装结果
final int flags:安装的参数,从market上下载的应用,安装参数为-r (replace)
@ frameworks/base/services/java/com/android/server/PackageManagerService.java
/* Called when a downloaded package installation has been confirmed by the user */
public void installPackage(final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
installPackage(packageURI, observer, flags, null);
}
/* Called when a downloaded package installation has been confirmed by the user */
public void installPackage(final Uri packageURI, final IPackageInstallObserver observer, final int flags,
final String installerPackageName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(packageURI, observer, flags,
installerPackageName);
mHandler.sendMessage(msg); // 安装过程非常耗时,所以使用了android的handler消息机制。
}
首先,参数封装成INIT_COPY message, 发到handlerThread,handlerThread收到message后, 将参数排队到mPendingInstalls中.
随后,MCS_BOUND流程将会处理这个队列, MCS_BOUND的整个安装流程借助了几个InstallParams和InstallArgs完成其中的参数和安装结果的传递,最终会调用processPendingInstall(), 进而调用到install过程的核心 installPackageLI()。
handleMessage()
--> doHandleMessage()
--> params.startCopy()
--> handleReturnCode()
--> processPendingInstall(mArgs, mRet)
--> installPackageLI(args, true, res);考虑了是否是新安装还是覆盖安装的情况。
private void installPackageLI(InstallArgs args,
boolean newInstall, PackageInstalledInfo res) {
...
boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);
boolean replace = false;
...
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
...
// Retrieve PackageSettings and parse package
...
// Get rid of all references to package scan path via parser.
...
if (replace) {
replacePackageLI(pkg, parseFlags, scanMode,
installerPackageName, res); // 覆盖安装
} else {
installNewPackageLI(pkg, parseFlags, scanMode,
installerPackageName,res); // 新安装
}
...
}
不管是新安装还是覆盖安装都会调用到函数scanPackageLI()中去,这个之后的流程就和系统应用一样了。
三、ADB安装apk
可以用3种方式来使用adb安装apk,直接push,adb install, abd shell pm。
直接push到system或者data的app目录,系统有实现自动监测这些app目录,只要有apk拷贝进来,会自动安装。
而后两种实现基本相同,adb instll的函数入口是frameworks/base/cmds/pm/src/com/android/commands/pm/pm.java,
adb shell pm实际上执行的一个linux命令,该命令没有源码,只有ELF文件位于目录frameworks/base/cmds/pm,编译的时候拷贝到system/bin目录下。见Android.mk文件:
include $(CLEAR_VARS)
ALL_PREBUILT += $(TARGET_OUT)/bin/pm
$(TARGET_OUT)/bin/pm : $(LOCAL_PATH)/pm | $(ACP)
$(transform-prebuilt-to-target)
分析pm.java的源码可以看出,pm.java中的各个函数的功能都是请求服务PackageManagerService中的接口来完成的。
public void run(String[] args) {
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
...
if ("install".equals(op)) {
runInstall();
return;
}
...
}
private void runInstall() {
int installFlags = 0;
String installerPackageName = null;
String opt;
while ((opt=nextOption()) != null) {
if (opt.equals("-l")) {
installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
} else if (opt.equals("-r")) { // 指定覆盖安装
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
} else if (opt.equals("-i")) {
installerPackageName = nextOptionData();
if (installerPackageName == null) {
System.err.println("Error: no value specified for -i");
showUsage();
return;
}
} else if (opt.equals("-t")) {
installFlags |= PackageManager.INSTALL_ALLOW_TEST;
} else if (opt.equals("-s")) {
// 指定安装至外部存储中,SD卡
installFlags |= PackageManager.INSTALL_EXTERNAL;
} else if (opt.equals("-f")) {
// 指定安装到内部flash
installFlags |= PackageManager.INSTALL_INTERNAL;
} else {
System.err.println("Error: Unknown option: " + opt);
showUsage();
return;
}
}
String apkFilePath = nextArg();
System.err.println("\tpkg: " + apkFilePath);
if (apkFilePath == null) {
System.err.println("Error: no package specified");
showUsage();
return;
}
PackageInstallObserver obs = new PackageInstallObserver();
try {
mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags, installerPackageName);
// 调用了和从Market下载的应用安装相同的接口
...
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
}
}
另外除了在pm后面跟上-s或者-f来指定apk安装位置之外,还可以使用pm的另外一个选项来指定:
adb shell pm setInstallLocation 0/1/2
0 [auto]: Let system decide the best location
1 [internal]: Install on internal device storage
2 [external]: Install on external media
而adb shell pm getInstallLocation可以得到当前的apk安装位置。
这是在命令行这样设置,然后再用adb install安装,或者直接在adb shell pm -r -s install来安装。
其实上面的设置如果要在代码中使用的话,可以在pm.java中找到可用接口runSetInstallLocation(),他实际上是调用了服务
PackageManagerService的接口:
public boolean setInstallLocation(int loc) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS, null);
if (getInstallLocation() == loc) {
return true;
}
if (loc == PackageHelper.APP_INSTALL_AUTO ||
loc == PackageHelper.APP_INSTALL_INTERNAL ||
loc == PackageHelper.APP_INSTALL_EXTERNAL) {
android.provider.Settings.System.putInt(mContext.getContentResolver(),
android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, loc);
return true;
}
return false;
}
为了使apk可以使用app2sd工具来转移,那么在写代码的时候,需要有下面信息存在:
1. 首先让你的程序支持SD卡上安装必须具备设置API Level至少为8,即androidmanifest.xml的中android:minSdkVersion至少为8这样你的APK最终运行时兼容的固件只有2.2了,同时在androidmanifest.xml文件的根节点中必须加入android:installLocation这个属性,类似代码如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="preferExternal"
... >
2. android:installLocation的值主要有preferExternal、auto和internalOnly这三个选项,通常我们设置为preferExternal可以优先推荐应用安装到SD卡上,当然最终用户可以选择为内部的ROM存储上,如果外部存储已满,Android内部也会安装到内部存储上,auto将会根据存储空间自适应,当然还有一些应用可能会有特殊的目的,他们一般必须安装在内部存储才能可靠运行,设置为internalOnly比较合适,主要体现在:
Services 服务
Alarm Services 闹铃提醒服务
Input Method Engines 输入法引擎
Live Wallpapers 活动壁纸
Live Folders 活动文件夹
App Widgets Widget
Account Managers 账户管理
Sync Adapters 同步适配器
Device Administrators 设备管理器
那么哪些应用适合安装在SD卡中呢? Android开发网建议一些占用资源比较大的游戏,比如大于3MB的单个文件,不需要长期驻留内存的应用,不具备提醒和实时监控的应用一般放到SD卡上比较合适,不过目前想让你的应用装到SD卡上,必须设置API Level至少为8以上,同时显示注明android:installLocation。
四、安装sd卡上的apk
把APK安装包保存在SD卡中,从手机里访问SD卡中的APK安装包,点击就可以启动安装界面,系统应用Packageinstaller.apk处理这种方式下的安装及卸载。
PackageInstallerActivity负责解析包,判断是否是可用的Apk文件
创建临时安装文件/data/data/com.android.packageinstaller/files/ApiDemos.apk
并启动安装确认界面startInstallConfirm,列出解析得到的该应用基本信息。如果手机上已安装有同名应用,则需要用户确认是否要替换安装。
确认安装后,启动InstallAppProgress,调用安装接口完成安装。
pm.installPackage(mPackageURI, observer, installFlags);
五、其他
data/system/packages.xml文件中,保存了手机上所有已安装应用的基本信息,如安装路径,申请的permission等信息。
参考网址:
http://topic.csdn.net/u/20110410/23/43571cfa-87b2-4e36-880c-1fa499ba32b0.html
PackageInstaller 原理简述
http://www.dayoo.com/roll/201009/25/10000307_103589200.htm
在Android 2.2上设置程序默认安装SD卡
http://www.cnblogs.com/wisekingokok/archive/2011/08/26/2154505.html
让Android应用程序支持安装到SD卡(APP2SD)
http://www.61ic.com/Mobile/Android/201106/35012.html
Android APK安装到SD卡
http://www.ylmf.net/android/tips/2011012421766.html
Android软件从手机内存转移到存储卡
http://www.cnblogs.com/youxilua/archive/2011/11/25/2263825.html
android Handler 机制研究学习笔记
file list:
1 Pm.java (frameworks\base\cmds\pm\src\com\android\commands\pm):2
2 PackageManagerService.java (frameworks\base\services\java\com\android\server)
3 Pm.java (frameworks\base\cmds\pm\src\com\android\commands\pm)
4 PackageManager.java (frameworks\base\core\java\android\content\pm)
5 Search Results
6 Handler.java (frameworks\base\core\java\android\os)
7 MountService.java (frameworks\base\services\java\com\android\server)
8 Message.java (frameworks\base\core\java\android\os)
9 HandlerThread.java (frameworks\base\core\java\android\os)
0 ServiceConnection.java (frameworks\base\core\java\android\content)
A Process.java (frameworks\base\core\java\android\os)
B Context.java (frameworks\base\core\java\android\content)
C InstallAppProgress.java (packages\apps\packageinstaller\src\com\android\packageinstaller)
D Installer.java (frameworks\base\services\java\com\android\server)
E Installer.java (frameworks\base\services\java\com\android\server):2
F LocalSocket.java (frameworks\base\core\java\android\net)
G LocalSocketImpl.java (frameworks\base\core\java\android\net)
H LocalSocketAddress.java (frameworks\base\core\java\android\net)
I PackageParser.java (frameworks\base\core\java\android\content\pm)
J System.java (libcore\luni\src\main\java\java\lang)
K Environment.java (frameworks\base\core\java\android\os)
L File.java (libcore\luni\src\main\java\java\io)
M ServiceManager.java (frameworks\base\core\java\android\os)
N ServiceManager.java (frameworks\base\tools\layoutlib\bridge\src\android\os)
O SystemServer.java (frameworks\base\services\java\com\android\server)
P ActivityManagerService.java (frameworks\base\services\java\com\android\server\am)
Q PackageHelper.java (frameworks\base\core\java\com\android\internal\content)
R PackageManagerTests.java (frameworks\base\core\tests\coretests\src\android\content\pm)
S Settings.java (frameworks\base\core\java\android\provider)
T ApplicationSettings.java (packages\apps\settings\src\com\android\settings)
U DatabaseHelper.java (frameworks\base\packages\settingsprovider\src\com\android\providers\settings)
V PackageManagerHostTestUtils.java (frameworks\base\core\tests\hosttests\src\android\content\pm)
W FileObserver.java (frameworks\base\core\java\android\os)
发表评论
-
Android锁屏的问题
2012-10-19 09:17 1382本文主要讨论Android锁屏的问题,具体有2个需求: 1、 ... -
android 修改开关机铃声
2012-10-18 16:52 18721,boot铃声,在surfaceflinger.cpp中re ... -
android输入法全屏问题
2012-10-18 15:18 1353两种方法: 一是在源码里进行修改。frameworks/bas ... -
android 解锁,锁屏流程
2012-10-16 15:36 7111解锁、锁屏界面状态改 ... -
android 从横屏到竖屏状态出现黑屏
2012-10-16 12:08 1847修改WindowManagerService.java中的pe ... -
android添加reboot选项
2012-10-13 15:33 15101,GlobalAction.java中mItems = Li ... -
手机硬件
2012-10-13 13:39 1023转自http://bbs.meizu.com/thread-4 ... -
Android编译后的文件结构
2012-10-09 18:57 861Android编译完成后,将在根目录中生成一个out文件夹,所 ... -
framework下资源文件---自定义统一的系统风格
2012-09-26 17:46 12311.系统资源文件位置:framework/base/core/ ... -
Android系统默认值的设置
2012-09-26 09:25 11831开机图片: android-logo-mask.png ... -
android 触屏反馈原理
2012-09-25 14:13 1800android中触屏反馈原理 HOPE mt6516 a ... -
Android下的系统Intent大全
2012-08-23 08:58 9761.从google搜索内容 Intent intent = n ... -
修改Android framework定制重启功能
2012-08-15 15:08 4261涉及到的源码(4.0) ics/frameworks/base ... -
Android makefile mk 重要参数解释及 通用模板编写
2012-08-10 09:04 17451. LOCAL_MODULE_TAGS解释: 控制此模块在什 ... -
手机的AP和BP是什么?
2012-08-06 15:56 1406手机的AP和BP根据上下文可以指代硬件和软件两种意思. 1) ... -
Android 上层界面到内核代码的完整的流程分析,以alarm为例子
2012-07-31 17:15 1355Alarm 调用流程,alarm的流程实现了从上层应用一直到下 ... -
彩信APN切换流程(framework)
2012-07-31 15:46 2067TransactionService之前的流程比较简单不在赘 ... -
我架设的程序员问答网站
2012-06-12 18:20 1225我架设了一个程序员问答网站,欢迎来http://program ... -
Android编译系统三
2012-06-15 10:33 1170android编译系统的makefile文件Android.m ... -
Android编译系统二
2012-06-08 14:46 2814一,Android编 译系统结构 android的编译文件 ...
相关推荐
matlab:基于遗传算法的多无人机协同任务分配 - 基于遗传算法的多无人机协同任务分配 - 种群中的每一个个体代表一次完整的任务分配方案,模型目标是找到代价函数的最小值,当作任务分配的最终方案 - 任务的代价评估分为两部分:无人机的总航程和消耗的总时间,分别设置了不同权重 - 注释详细。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。
Matlab领域上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作
水果销售系统系统主要功能: a.系统功能模块: 首页,门店,商品信息,公告资讯,个人中心,后台管理,购物车,投诉反馈等 b.管理员功能模块: 首页,个人中心,门店管理,用户管理,商品分类管理,商品信息管理,商品咨询管理,系统管理等 c.用户功能模块: 首页,个人中心,商品咨询管理,我的收藏管理等 d.门店功能模块: 首页,个人中心,商品信息管理,商品咨询管理,订单管理等功能 关键技术: MYSQL、Python、Django、vue 【技术支持】项目均已测试可正常运行,调试问题可私 【内容包含】源码+数据库+开发文档+lun w....,快速上手。
前一段时间一直有这个问题,新建文件和文件夹、改名都不更新,必须按F5刷新出来了,每次都要按F5刷新一次。删除文件、移动文件什么的都不会显示出来,一直没搞清楚什么原因,遇到问题, 1、请先试试删除本机是否连接到了别的计算机的共享目录,有的话先删除试试。 2、如果1不可行,再试试我的电脑的文件夹选项/查看,重置下默认值。 3、如果再不行就实施本办法...... 注意不需要重启,只需要打开任务管理器,把资源管理器重启一下即可
无刷直流电机BLDC sinulink仿真 无刷直流电机双闭环PId控制 1)主要由DC直流源、三相逆变桥、无刷直流电机、PWM发生器、霍尔位置解码模块、驱动信号模块、PID、示波器等构成。 2)采用转速环、电流环双闭环控制算法; 3)转速环采用PID控制; 4)电流环采用PID控制;
四轮转向汽车模型预测控制(MPC)路径跟踪 simulink-simscape仿真,无需carsim。 mpc基于车辆动力学模型设计,纵向PID控制。 支持平坦路面,颠簸路面切,外形变化。 魔术公式轮胎模型。 注:MATLAB要求2022a及以上版本
资源说明: 1:csdn平台资源详情页的文档预览若发现'异常',属平台多文档混合解析和叠加展示风格,请放心使用。 2:32页图文详解文档(从零开始项目全套环境工具安装搭建调试运行部署,保姆级图文详解)。 3:34页范例参考毕业论文,万字长文,word文档,支持二次编辑。 4:27页范例参考答辩ppt,pptx格式,支持二次编辑。 5:工具环境、ppt参考模板、相关教程资源分享。 6:资源项目源码均已通过严格测试验证,保证能够正常运行,本项目仅用作交流学习参考,请切勿用于商业用途。 7:项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通。 内容概要: 本系统基于 B/S 网络结构,在IDEA中开发。服务端用 Java 并借 ssm 框架(Spring+SpringMVC+MyBatis)搭建后台。前台采用支持 HTML5 的 VUE 框架。用 MySQL 存储数据,可靠性强。 能学到什么: 学会用ssm搭建后台,提升效率、专注业务。学习 VUE 框架构建交互界面、前后端数据交互、MySQL管理数据、从零开始环境搭建、调试、运行、打包、部署流程。
资源说明: 1:csdn平台资源详情页的文档预览若发现'异常',属平台多文档混合解析和叠加展示风格,请放心使用。 2:32页图文详解文档(从零开始项目全套环境工具安装搭建调试运行部署,保姆级图文详解)。 3:34页范例参考毕业论文,万字长文,word文档,支持二次编辑。 4:27页范例参考答辩ppt,pptx格式,支持二次编辑。 5:工具环境、ppt参考模板、相关教程资源分享。 6:资源项目源码均已通过严格测试验证,保证能够正常运行,本项目仅用作交流学习参考,请切勿用于商业用途。 7:项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通。 内容概要: 本系统基于 B/S 网络结构,在 IDEA 中开发。服务端用 Java 并借 ssm 框架(Spring+SpringMVC+MyBatis)搭建后台。用 MySQL 存储数据,可靠性强。 能学到什么: 学会用ssm搭建后台,提升效率、专注业务。学习使用jsp、html构建交互界面、前后端数据交互、MySQL管理数据、从零开始环境搭建、调试、运行、打包、部署流程。
风光出力场景生成与消减 可采用蒙特卡洛模拟和拉丁超立方生成光伏和风电出力场景,并采用快速前推法或同步回代消除法进行削减,可以对生成场景数和削减数据进行修改。 可增加负荷功率的场景生成与削减,根据需求进行修改-改进
四柱印刷机sw18可编辑全套技术资料100%好用.zip
资源说明: 1:csdn平台资源详情页的文档预览若发现'异常',属平台多文档混合解析和叠加展示风格,请放心使用。 2:32页图文详解文档(从零开始项目全套环境工具安装搭建调试运行部署,保姆级图文详解)。 3:34页范例参考毕业论文,万字长文,word文档,支持二次编辑。 4:27页范例参考答辩ppt,pptx格式,支持二次编辑。 5:工具环境、ppt参考模板、相关教程资源分享。 6:资源项目源码均已通过严格测试验证,保证能够正常运行,本项目仅用作交流学习参考,请切勿用于商业用途。 7:项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通。 内容概要: 本系统基于 B/S 网络结构,在 IDEA 中开发。服务端用 Java 并借 ssm 框架(Spring+SpringMVC+MyBatis)搭建后台。用 MySQL 存储数据,可靠性强。 能学到什么: 学会用ssm搭建后台,提升效率、专注业务。学习使用jsp、html构建交互界面、前后端数据交互、MySQL管理数据、从零开始环境搭建、调试、运行、打包、部署流程。
工厂垂直提升机sw14可编辑全套技术资料100%好用.zip
MATLAB代码:面向削峰填谷的电动汽车多目标优化调度策略 关键词:电动汽车 削峰填谷 多目标 充放电优化 参考文档:自己整理的说明文档,公式、约束、数据齐全,可联系我查看 仿真平台:MATLAB YALMIP+CPLEX 优势:代码注释详实,出图效果非常好,说明文档细致详细,模型精准 主要内容:代码主要实现了考虑电动汽车参与削峰填谷的场景下,电动汽车充放电策略的优化,是一个多目标优化,目标函数一方面考虑了电动汽车综合负荷以及电池 化损耗成本,一方面考虑了削峰填谷的峰谷差和负荷波动最低,所以为三目标约束,最后通过赋权值以及化简将三目标问题化简为单目标问题进行求解,求解结果可以看出来电动汽车参与后,负荷曲线有明显改善,结果合理正确。
感应电机 异步电机模型预测磁链控制MPFC 感应电机MPFC系统将逆变器电压矢量遍历代入到定子磁链预测模型,可得到下一时刻的定子磁链(定子磁链参考值可由等效替得到),将预测得到的定子磁链代入到表征系统控制性能的成本函数,并将令成本函数最小的电压矢量作为输出。 提供对应的参考文献;
彼得森经济研究所-美国是否正在经历一场将提振中产阶级的制造业复兴
Python培训之美眉图片下载爬虫 06 读回模特个人网站内容
使用 Python 和 Tkinter 库创建新年倒计时程序 新的一年即将到来,我们不妨通过一个简单又有趣的 Python 程序来迎接它!今天,我们将使用 Python 的 Tkinter 库,创建一个新年倒计时的窗口程序。通过加载背景图片,使用 Label 组件实时显示倒计时(天数、小时数、分钟数、秒数),并通过每秒更新一次时间,来提醒你新年的到来。 这个新年倒计时程序的代码结构简洁,功能清晰,适合 Python 初学者学习和理解。通过这个项目,你可以了解如何使用 Tkinter 创建图形用户界面、如何操作时间以及如何在窗口中动态更新内容。你可以根据自己的需求进一步优化程序,例如增加一些动画效果、设置不同的字体样式或者改变背景图片等。 希望这篇博客能帮助你理解 Tkinter 的基本用法,并激发你尝试更多有趣的项目!
【课程设计】使用Python调用OpenAI接口-OpenAI接口调用python库源码.zip
桁架结构有限元程序的一般过程,利用matlab有限元来计算二维桁架的固有频率。资源来源于网络分享,如有侵权请告知!
【java】基于rabbitmq解决分布式事务问题