范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

工作日报2022。4。19PackageManagerService扫描APK目录

  2022.4.19问题澄清;
  witen 5.1 升级到 bturnc 5.3无imei绑定用户选项澄清;应用平台设备鉴权822优化,合入工具类修改、及基本功能验证,非记录仪数据存入缓存,coding 20%;代码仓readme文件创建;
  6 扫描APK目录
  PackageManagerService的构造函数中调用了scanDirTracedLI方法来扫描某个目录的apk文件。
  Android 10.0中,PKMS主要扫描以下路径的APK信息:
  /vendor/overlay
  /product/overlay
  /product_services/overlay
  /odm/overlay
  /oem/overlay
  /system/framework
  /system/priv-app
  /system/app
  /vendor/priv-app
  /vendor/app
  /odm/priv-app
  /odm/app
  /oem/app
  /oem/priv-app
  /product/priv-app
  /product/app
  /product_services/priv-app
  /product_services/app
  /product_services/priv-app
  我们就scanDirTracedLI()为入口来进行分析:
  6.1 [ParallelPackageParser.java] scanDirTracedLI()
  从下面的函数可见,scanDirTracedLI的入口很简单,首先加入了一些systtrace的日志追踪,然后调用scanDirLI()进行分析
  private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) {
  Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
  try {
  scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
  } finally {
  Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  }
  }
  6.2 [ParallelPackageParser.java] scanDirLI()
  scanDirLI()中使用了ParallelPackageParser的对象,ParallelPackageParser是一个队列,我们这里手机所有系统的apk,然后从这些队列里面取出apk,再调用PackageParser 解析进行解析
  private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
  final File[] files = scanDir.listFiles();
  if (ArrayUtils.isEmpty(files)) {
  Log.d(TAG, "No files in app dir " + scanDir);
  return;
  }
  if (DEBUG_PACKAGE_SCANNING) {
  Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
  + " flags=0x" + Integer.toHexString(parseFlags));
  }
  //parallelPackageParser是一个队列,收集系统 apk 文件,
  //然后从这个队列里面一个个取出 apk ,调用 PackageParser 解析
  try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
  mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
  mParallelPackageParserCallback)) {
  // Submit files for parsing in parallel
  int fileCount = 0;
  for (File file : files) {
  //是Apk文件,或者是目录
  final boolean isPackage = (isApkFile(file) || file.isDirectory())
  && !PackageInstallerService.isStageName(file.getName());
  过滤掉非 apk 文件,如果不是则跳过继续扫描
  if (!isPackage) {
  // Ignore entries which are not packages
  continue;
  }
  //把APK信息存入parallelPackageParser中的对象mQueue,PackageParser()函数赋给了队列中的pkg成员
  //参考[6.3]
  parallelPackageParser.submit(file, parseFlags);
  fileCount++;
  }
  // Process results one by one
  for (; fileCount > 0; fileCount--) {
  //从parallelPackageParser中取出队列apk的信息
  ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
  Throwable throwable = parseResult.throwable;
  int errorCode = PackageManager.INSTALL_SUCCEEDED;
  if (throwable == null) {
  // TODO(toddke): move lower in the scan chain
  // Static shared libraries have synthetic package names
  if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
  renameStaticSharedLibraryPackage(parseResult.pkg);
  }
  try {
  //调用 scanPackageChildLI 方法扫描一个特定的 apk 文件
  // 该类的实例代表一个 APK 文件,所以它就是和 apk 文件对应的数据结构。
  //参考[6.4]
  scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
  currentTime, null);
  } catch (PackageManagerException e) {
  errorCode = e.error;
  Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
  }
  } else if (throwable instanceof PackageParser.PackageParserException) {
  PackageParser.PackageParserException e = (PackageParser.PackageParserException)
  throwable;
  errorCode = e.error;
  Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
  } else {
  throw new IllegalStateException("Unexpected exception occurred while parsing "
  + parseResult.scanFile, throwable);
  }
  // Delete invalid userdata apps
  //如果是非系统 apk 并且解析失败
  if ((scanFlags & SCAN_AS_SYSTEM) == 0 &&
  errorCode != PackageManager.INSTALL_SUCCEEDED) {
  logCriticalInfo(Log.WARN,
  "Deleting invalid package at " + parseResult.scanFile);
  // 非系统 Package 扫描失败,删除文件
  removeCodePathLI(parseResult.scanFile);
  }
  }
  }
  }
  6.3 [ParallelPackageParser.java] submit
  把扫描路径中的APK等内容,放入队列mQueue,并把parsePackage()赋给ParseResult,用于后面的调用
  public void submit(File scanFile, int parseFlags) {
  mService.submit(() -> {
  ParseResult pr = new ParseResult();
  Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
  try {
  PackageParser pp = new PackageParser();
  pp.setSeparateProcesses(mSeparateProcesses);
  pp.setOnlyCoreApps(mOnlyCore);
  pp.setDisplayMetrics(mMetrics);
  pp.setCacheDir(mCacheDir);
  pp.setCallback(mPackageParserCallback);
  pr.scanFile = scanFile;
  pr.pkg = parsePackage(pp, scanFile, parseFlags);
  } catch (Throwable e) {
  pr.throwable = e;
  } finally {
  Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  }
  try {
  mQueue.put(pr);
  } catch (InterruptedException e) {
  Thread.currentThread().interrupt();
  // Propagate result to callers of take().
  // This is helpful to prevent main thread from getting stuck waiting on
  // ParallelPackageParser to finish in case of interruption
  mInterruptedInThread = Thread.currentThread().getName();
  }
  });
  }
  通过parsePackage 进行apk解析,如果传入的packageFile是目录,调用parseClusterPackage()解析,
  如果传入的是APK文件,就调用parseMonolithicPackage()解析
  public Package parsePackage(File packageFile, int flags, boolean useCaches)
  throws PackageParserException {
  ...
  if (packageFile.isDirectory()) {
  //如果传入的packageFile是目录,调用parseClusterPackage()解析
  parsed = parseClusterPackage(packageFile, flags);
  } else {
  //如果是APK文件,就调用parseMonolithicPackage()解析
  parsed = parseMonolithicPackage(packageFile, flags);
  }
  ...
  return parsed;
  }
  我们先来看看parseClusterPackage()
  作用:解析给定目录中包含的所有apk,将它们视为单个包。这还可以执行完整性检查,比如需要相同的包名和版本代码、单个基本APK和惟一的拆分名称
  首先通过parseClusterPackageLite()对目录下的apk文件进行初步分析,主要区别是核心应用还是非核心应用。核心应用只有一个,非核心应用可以没有,或者多个,非核心应用的作用主要用来保存资源和代码。然后对核心应用调用parseBaseApk分析并生成Package。对非核心应用调用parseSplitApk,分析结果放在前面的Package对象中
  private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
  //获取应用目录的PackageLite对象,这个对象分开保存了目录下的核心应用以及非核心应用的名称
  final PackageLite lite = parseClusterPackageLite(packageDir, 0);
  //如果lite中没有核心应用,退出
  if (mOnlyCoreApps && !lite.coreApp) {
  throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
  "Not a coreApp: " + packageDir);
  }
  // Build the split dependency tree.
  //构建分割的依赖项树
  SparseArray splitDependencies = null;
  final SplitAssetLoader assetLoader;
  if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
  try {
  splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
  assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
  } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
  throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
  }
  } else {
  assetLoader = new DefaultSplitAssetLoader(lite, flags);
  }
  try {
  final AssetManager assets = assetLoader.getBaseAssetManager();
  final File baseApk = new File(lite.baseCodePath);
  //对核心应用解析
  final Package pkg = parseBaseApk(baseApk, assets, flags);
  if (pkg == null) {
  throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
  "Failed to parse base APK: " + baseApk);
  }
  if (!ArrayUtils.isEmpty(lite.splitNames)) {
  final int num = lite.splitNames.length;
  pkg.splitNames = lite.splitNames;
  pkg.splitCodePaths = lite.splitCodePaths;
  pkg.splitRevisionCodes = lite.splitRevisionCodes;
  pkg.splitFlags = new int[num];
  pkg.splitPrivateFlags = new int[num];
  pkg.applicationInfo.splitNames = pkg.splitNames;
  pkg.applicationInfo.splitDependencies = splitDependencies;
  pkg.applicationInfo.splitClassLoaderNames = new String[num];
  for (int i = 0; i < num; i++) {
  final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
  //对非核心应用的处理
  parseSplitApk(pkg, i, splitAssets, flags);
  }
  }
  pkg.setCodePath(packageDir.getCanonicalPath());
  pkg.setUse32bitAbi(lite.use32bitAbi);
  return pkg;
  } catch (IOException e) {
  throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
  "Failed to get path: " + lite.baseCodePath, e);
  } finally {
  IoUtils.closeQuietly(assetLoader);
  }
  }
  再看parseMonolithicPackage(),它的作用是解析给定的APK文件,将其作为单个单块包处理。
  最终也是调用parseBaseApk()进行解析,我们接下来看下parseBaseApk()
  public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
  final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
  if (mOnlyCoreApps) {
  if (!lite.coreApp) {
  throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
  "Not a coreApp: " + apkFile);
  }
  }
  final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
  try {
  //对核心应用解析
  final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags);
  pkg.setCodePath(apkFile.getCanonicalPath());
  pkg.setUse32bitAbi(lite.use32bitAbi);
  return pkg;
  } catch (IOException e) {
  throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
  "Failed to get path: " + apkFile, e);
  } finally {
  IoUtils.closeQuietly(assetLoader);
  }
  }
  parseBaseApk()主要是对AndroidManifest.xml进行解析,解析后所有的信息放在Package对象中。
  private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
  throws PackageParserException {
  final String apkPath = apkFile.getAbsolutePath();
  ...
  XmlResourceParser parser = null;
  ...
  final int cookie = assets.findCookieForPath(apkPath);
  if (cookie == 0) {
  throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
  "Failed adding asset path: " + apkPath);
  }
  //获得一个 XML 资源解析对象,该对象解析的是 APK 中的 AndroidManifest.xml 文件。
  parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
  final Resources res = new Resources(assets, mMetrics, null);
  final String[] outError = new String[1];
  //再调用重载函数parseBaseApk()最终到parseBaseApkCommon(),解析AndroidManifest.xml 后得到一个Package对象
  final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
  ...
  pkg.setVolumeUuid(volumeUuid);
  pkg.setApplicationVolumeUuid(volumeUuid);
  pkg.setBaseCodePath(apkPath);
  pkg.setSigningDetails(SigningDetails.UNKNOWN);
  return pkg;
  ...
  }
  从AndroidManifest.xml中获取标签名,解析标签中的各个item的内容,存入Package对象中
  例如获取标签"application"、"permission"
  private Package parseBaseApkCommon(Package pkg, Set acceptedTags, Resources res,
  XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
  IOException {
  TypedArray sa = res.obtainAttributes(parser,
  com.android.internal.R.styleable.AndroidManifest);
  //拿到AndroidManifest.xml 中的sharedUserId, 一般情况下有"android.uid.system"等信息
  String str = sa.getNonConfigurationString(
  com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
  while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
  && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
  //从AndroidManifest.xml中获取标签名
  String tagName = parser.getName();
  //如果读到AndroidManifest.xml中的tag是"application",执行parseBaseApplication()进行解析
  if (tagName.equals(TAG_APPLICATION)) {
  if (foundApp) {
  ...
  }
  foundApp = true;
  //解析"application"的信息,赋值给pkg
  if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
  return null;
  }
  ...
  //如果标签是"permission"
  else if (tagName.equals(TAG_PERMISSION)) {
  //进行"permission"的解析
  if (!parsePermission(pkg, res, parser, outError)) {
  return null;
  }
  ....
  }
  }
  }
  }
  上面解析AndroidManifest.xml,
  会得到"application"、"overlay"、"permission"、"uses-permission"等信息
  我们下面就针对"application"进行展开分析一下,进入parseBaseApplication()函数
  private boolean parseBaseApplication(Package owner, Resources res,
  XmlResourceParser parser, int flags, String[] outError)
  while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
  && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
  //获取"application"子标签的标签内容
  String tagName = parser.getName();
  //如果标签是"activity"
  if (tagName.equals("activity")) {
  //解析Activity的信息,把activity加入Package对象
  Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
  owner.baseHardwareAccelerated);
  if (a == null) {
  mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
  return false;
  }
  hasActivityOrder |= (a.order != 0);
  owner.activities.add(a);
  } else if (tagName.equals("receiver")) {
  //如果标签是"receiver",获取receiver信息,加入Package对象
  Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
  true, false);
  if (a == null) {
  mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
  return false;
  }
  hasReceiverOrder |= (a.order != 0);
  owner.receivers.add(a);
  }else if (tagName.equals("service")) {
  //如果标签是"service",获取service信息,加入Package对象
  Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
  if (s == null) {
  mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
  return false;
  }
  hasServiceOrder |= (s.order != 0);
  owner.services.add(s);
  }else if (tagName.equals("provider")) {
  //如果标签是"provider",获取provider信息,加入Package对象
  Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
  if (p == null) {
  mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
  return false;
  }
  owner.providers.add(p);
  }
  ...
  }
  }
  在 PackageParser 扫描完一个 APK 后,此时系统已经根据该 APK 中 AndroidManifest.xml,创建了一个完整的 Package 对象,
  下一步就是将该 Package 加入到系统中。此时调用的函数就是另外一个 scanPackageChildLI
  6.4 [PackageManagerService.java] scanPackageChildLI()
  调用addForInitLI()在platform初始化时,把Package内容加入到内部数据结构
  private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
  final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
  @Nullable UserHandle user)
  throws PackageManagerException {
  ...
  // Scan the parent
  PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
  scanFlags, currentTime, user);
  // Scan the children
  final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
  for (int i = 0; i < childCount; i++) {
  PackageParser.Package childPackage = pkg.childPackages.get(i);
  //在平台初始化期间向内部数据结构添加新包。
  //在platform初始化时,把Package内容加入到内部数据结构,
  addForInitLI(childPackage, parseFlags, scanFlags,
  currentTime, user);
  }
  if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
  return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
  }
  }
  在addForInitLI()中,进行安装包校验、签名检查、apk更新等操作,把Package加入系统
  private PackageParser.Package addForInitLI(PackageParser.Package pkg,
  @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
  @Nullable UserHandle user)
  throws PackageManagerException {
  // 判断系统应用是否需要更新
  synchronized (mPackages) {
  // 更新子应用
  if (isSystemPkgUpdated) {
  ...
  }
  if (isSystemPkgBetter) {
  // 更新安装包到 system 分区中
  synchronized (mPackages) {
  // just remove the loaded entries from package lists
  mPackages.remove(pkgSetting.name);
  }
  ...
  // 创建安装参数 InstallArgs
  final InstallArgs args = createInstallArgsForExisting(
  pkgSetting.codePathString,
  pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
  args.cleanUpResourcesLI();
  synchronized (mPackages) {
  mSettings.enableSystemPackageLPw(pkgSetting.name);
  }
  }
  // 安装包校验
  collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);
  ...
  try (PackageFreezer freezer = freezePackage(pkg.packageName,
  "scanPackageInternalLI")) {
  // 如果两个 apk 签名不匹配,则调用 deletePackageLIF 方法清除 apk 文件及其数据
  deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
  }
  ...
  // 更新系统 apk 程序
  InstallArgs args = createInstallArgsForExisting(
  pkgSetting.codePathString,
  pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
  synchronized (mInstallLock) {
  args.cleanUpResourcesLI();
  }
  }
  // 如果新安装的系统APP 会被旧的APP 数据覆盖,所以需要隐藏隐藏系统应用程序,并重新扫描 /data/app 目录
  if (shouldHideSystemApp) {
  synchronized (mPackages) {
  mSettings.disableSystemPackageLPw(pkg.packageName, true);
  }
  }
  }
  回顾一下整个APK的扫描过程:
  按照core app >system app > other app 优先级扫描APK,解析AndroidManifest.xml文件,得到各个标签内容
  解析XML文件得到的信息由 Package 保存。从该类的成员变量可看出,和 Android 四大组件相关的信息分别由 activites、receivers、providers、services 保存。由于一个 APK 可声明多个组件,因此 activites 和 receivers等均声明为 ArrayList。
  在 PackageParser 扫描完一个 APK 后,此时系统已经根据该 APK 中 AndroidManifest.xml,创建了一个完整的 Package 对象,下一步就是将该 Package 加入到系统中
  非系统 Package 扫描失败,删除文件

现在很多诈骗,骚扰电话都是虚拟号码,为什么不把虚拟号码禁用掉?利益而已,互联网不断快速的发展中,个人隐私信息倒卖严重,骗子通过网络虚拟电话软件结合隐私信息可以精准诈骗而债务催收公司通过向原债主(包括但不限于银行金融公司互联网金融平台小贷公司和头条里面电信移动联通那么多便宜套餐广告,为什么营业厅里没有?今天,就来讲一讲广告学和广告策略。广告不仅是打出知名度,它还有一个作用,就是故意制造信息的不对称,让你搞不懂,最终你只能选一个搞得懂的,然后多花钱了。不仅是通讯行业,其实各行各业都逃离舒适圈,人工智能500万人才缺口将由谁来填补?金九银十,又到了一年一度毕业生找工作的高峰期。教育部数据显示,2021年我国高校毕业生总规模达到909万人,比上年高出35万人。而从毕业生就业行业来看,IT通信电子互联网成为毕业生一眼就能让你心水的蓝牙耳机,小巧易携的无线蓝牙耳机推荐给你们前段时间和朋友们出去玩疯狂大摆锤,把用了好久的Airpodspro搞丢了,好心痛自己还在上学,一直也没舍得再买一个,这不最近搞到了点小钱,迫不及待地想要新耳机啦没有蓝牙耳机陪伴的那苹果被针对性立法,iPhone13充电线被砍最近这几天,又被一条消息刷屏了。原因是欧盟委员会将在下个月提交立法,使在欧盟内的手机和其他电子设备采用通用充电器。根据欧盟调查显示,2018年欧盟在售手机充电中,有一半使用USBm苹果id账号忘了怎么办?您好!我是捌零玖零电子馆,很荣幸为您解答这个问题。AppleID对每一个苹果设备至关重要,如果没有AppleID很多苹果设备功能都不能正常使用。那么当我们不小心忘记了AppleIDOPPOFindX4Pro概念机大曝光160Hz屏6000mAh大电池Tech分析狮8月22日消息,熟悉OPPO这个手机品牌的人应该知道,该品牌最强旗舰机系列就是Find系列。而日前被曝光的OPPOFindX4Pro这款概念机,则格外引人注目。下面我互联网企业的竞争力在哪里强大的供应链体系?还是合作共赢?互联网如今的世界,走到哪里都离不开互联网的身影,越来越多的厂家也将产品的互联网化作为企业的盈利方式,毕竟产品的终极目标是要销售出去,目前来看最廉价也是最容易实现的宣传和推广模式就是被亚马逊们围剿的企业,是时候独立门户了随着平台经济的崛起,平台掌握了越来越多的流量议价权,但这实际上导致了平台已经成为品牌商家的新甲方,而品牌商家实际上在为平台服务。一步步掉入流量陷阱的品牌商对于平台独大,压迫品牌等现击败英特尔台积电,韩国巨头登顶全球第一,靠卖芯片吸金1320亿提起三星,多数人的第一印象还是手机巨头。殊不知,三星还有另外一个更加重量级的身份,这便是可以比肩英特尔和台积电的半导体大厂。三星电子登顶第一市场调研机构ICInsights的数据显独立8个月发布首款高端旗舰机,荣耀瞄准苹果要夺回市场过去一段时间,因为华为缺席,苹果和三星分食了全球高端智能手机市场绝大部分份额。有数据显示,今年一季度,全球智能手机收入突破1000亿美元大关。在收入份额前十的机型中,苹果和三星共占
家族中的顶级SUV全新丰田红杉假想图曝光近日,有海外媒体曝光了一组全新丰田红杉的假想图。新车将与全新坦途共用平台与动力,后轮将采用独立悬挂并标配三排座椅。外观方面,假想图中的新车形象借鉴了全新坦途TRDPro车型的设计,广汽丰田第三款兰达车型丰田锋兰达将于今年年底上市我们从广汽丰田获取的最新消息,广汽丰田旗下的全新紧凑型SUV已正式命名,新车中文名为锋兰达,计划在2021年年底正式上市。外观方面,通过官方发布的预告图来看,锋兰达的外观将延续日版1。5L动力的7座SUV全新本田BRV海外首发日前,本田在海外市场发布了全新换代车型全新本田BRV,本田BRV是一款针对东南亚市场的车型,2015年至今已售出了25。5万辆。外观方面,新车外观比上一代BRV有很大提升,大尺寸梯这才是越野机器?Jeep牧马人威利斯XtremeRecon套件版海外发售日前,Jeep品牌在2021底特律4Fest活动中发布了牧马人威利斯XtremeRecon套件版,新车的起售价为39435美元(约合人民币25。5万元)。外观方面,新车外观采用了军新款日产劲客官图发布将于9月29日上市9月22日,东风日产发布了新款劲客官图。新款劲客的颜值与配置都有明显提升,计划在9月29日天津车展上正式上市。外观方面,新车外观延续了海外版新款劲客的设计,其中大灯组的造型较为凌厉再不担心费油了纯电皮卡福特F150Lighting开始试生产近日,我们从福特官方获悉,全新福特F150Lightning已于福特密歇根州工厂开始试生产。福特F150Lighting是一款纯电皮卡,续航里程最高可达482km。新车将于2022太贵了?广汽丰田赛那开启预售9月21日,广汽丰田旗下的中大型MPV丰田赛那正式开启预售,6款车型的预售价在32万42万元之间。用户可通过丰云行APP线上订车,以避免经销商的加价行为。外观方面,广汽丰田赛那沿袭Windows11初体验大家好,这里是事件笨身,最近我通过微软的用户体验计划顺利升级了windows11,在短暂使用几天后和大家一起聊下使用感受。一环境介绍(1)电脑型号(2)系统版本二使用感受(1)外观职场避坑指南在职场中,有很多坑,却是我们平常忽略的。踩到之后才后悔莫及,我现在把一些坑指出来,用3个例子来说明,让各位在职场中更加如鱼得水。第一个坑越级汇报李明是一家公司的业务骨干,有一次他想房地产贷款有红线,个人住房贷款也有红线,房贷新规剑指何方?房贷新规华说2020年12月31日,央行和银监会联合下发了一个通知。通知说,从2021年1月1日起,国内所有的中资银行包括商业银行开发性银行和政策性银行都必须执行房地产贷款集中度管2020中国之年中国之年华说时光荏苒。此刻现在,已是2020年的岁末。这是非比寻常的一年,于中国如是,于世界亦如是。不寻常,是因为这一年瘟疫流行猖獗,是为大疫之年。这瘟疫之名,曰新型冠状病毒感染肺