学习日记-2022-02-24

framework

PackageManageService

在开机的时候,会先去扫瞄系统目录下的apk,再去扫瞄普通apk,解析他们的清单信息吧他们加载到内存里,之前我一直以为,解析完后会吧对应的apk的清单信息,保存在数据库或者xml里
方便下次读取,现在看起来不是,比如我们push个apk到system/app,他下次开机就有了,扫瞄只有开机会扫,每次都是全部解析

解析apk的类为PackageParse2

@AnyThread
    public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
            throws PackageParserException {
        ''''''
        ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
             ''''''
    }

进入ParsingPackageUtils,这里可以看到获取assetmanager 以及resource通过assetmanager初始化的过程

 private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
            String codePath, SplitAssetLoader assetLoader, int flags)
            throws PackageParserException {
        final String apkPath = apkFile.getAbsolutePath();

        String volumeUuid = null;
        if (apkPath.startsWith(MNT_EXPAND)) {
            final int end = apkPath.indexOf('/', MNT_EXPAND.length());
            volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
        }

        if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);

        final AssetManager assets = assetLoader.getBaseAssetManager();
        final int cookie = assets.findCookieForPath(apkPath);
        if (cookie == 0) {
            return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                    "Failed adding asset path: " + apkPath);
        }

        try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
                ANDROID_MANIFEST_FILENAME)) {
            final Resources res = new Resources(assets, mDisplayMetrics, null);

            ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
                    parser, flags);
            if (result.isError()) {
                return input.error(result.getErrorCode(),
                        apkPath + " (at " + parser.getPositionDescription() + "): "
                                + result.getErrorMessage());
            }

            final ParsingPackage pkg = result.getResult();
            if (assets.containsAllocatedTable()) {
                final ParseResult<?> deferResult = input.deferError(
                        "Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires"
                                + " the resources.arsc of installed APKs to be stored uncompressed"
                                + " and aligned on a 4-byte boundary",
                        DeferredError.RESOURCES_ARSC_COMPRESSED);
                if (deferResult.isError()) {
                    return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,
                            deferResult.getErrorMessage());
                }
            }

            ApkAssets apkAssets = assetLoader.getBaseApkAssets();
            boolean definesOverlayable = false;
            try {
                definesOverlayable = apkAssets.definesOverlayable();
            } catch (IOException ignored) {
                // Will fail if there's no packages in the ApkAssets, which can be treated as false
            }

            if (definesOverlayable) {
                SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
                int size = packageNames.size();
                for (int index = 0; index < size; index++) {
                    String packageName = packageNames.valueAt(index);
                    Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
                    if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
                        for (String overlayable : overlayableToActor.keySet()) {
                            pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
                        }
                    }
                }
            }

            pkg.setVolumeUuid(volumeUuid);

            if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
                pkg.setSigningDetails(getSigningDetails(pkg, false));
            } else {
                pkg.setSigningDetails(SigningDetails.UNKNOWN);
            }

            return input.success(pkg);
        } catch (Exception e) {
            return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                    "Failed to read manifest from " + apkPath, e);
        }
    }

获取am开始解析application的流程,,会在里面执行parseActivity,parseService,parseProvider等解析四大组件的流程,并把这些组建信息保存到 ParsingPackage这个类里

   private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
            ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
            throws XmlPullParserException, IOException {
        final String pkgName = pkg.getPackageName();
        int targetSdk = pkg.getTargetSdkVersion();

        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication);
        try {
            // TODO(b/135203078): Remove this and force unit tests to mock an empty manifest
            // This case can only happen in unit tests where we sometimes need to create fakes
            // of various package parser data structures.
            if (sa == null) {
                return input.error("<application> does not contain any attributes");
            }

            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestApplication_name,
                    0);
            if (name != null) {
                String packageName = pkg.getPackageName();
                String outInfoName = ParsingUtils.buildClassName(packageName, name);
                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
                    return input.error("<application> invalid android:name");
                } else if (outInfoName == null) {
                    return input.error("Empty class name in package " + packageName);
                }

                pkg.setClassName(outInfoName);
            }

            TypedValue labelValue = sa.peekValue(R.styleable.AndroidManifestApplication_label);
            if (labelValue != null) {
                pkg.setLabelRes(labelValue.resourceId);
                if (labelValue.resourceId == 0) {
                    pkg.setNonLocalizedLabel(labelValue.coerceToString());
                }
            }

            parseBaseAppBasicFlags(pkg, sa);

            String manageSpaceActivity = nonConfigString(Configuration.NATIVE_CONFIG_VERSION,
                    R.styleable.AndroidManifestApplication_manageSpaceActivity, sa);
            if (manageSpaceActivity != null) {
                String manageSpaceActivityName = ParsingUtils.buildClassName(pkgName,
                        manageSpaceActivity);

                if (manageSpaceActivityName == null) {
                    return input.error("Empty class name in package " + pkgName);
                }

                pkg.setManageSpaceActivityName(manageSpaceActivityName);
            }

            if (pkg.isAllowBackup()) {
                // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
                // and restoreAnyVersion are only relevant if backup is possible for the
                // given application.
                String backupAgent = nonConfigString(Configuration.NATIVE_CONFIG_VERSION,
                        R.styleable.AndroidManifestApplication_backupAgent, sa);
                if (backupAgent != null) {
                    String backupAgentName = ParsingUtils.buildClassName(pkgName, backupAgent);
                    if (backupAgentName == null) {
                        return input.error("Empty class name in package " + pkgName);
                    }

                    if (DEBUG_BACKUP) {
                        Slog.v(TAG, "android:backupAgent = " + backupAgentName
                                + " from " + pkgName + "+" + backupAgent);
                    }

                    pkg.setBackupAgentName(backupAgentName)
                            .setKillAfterRestore(bool(true,
                                    R.styleable.AndroidManifestApplication_killAfterRestore, sa))
                            .setRestoreAnyVersion(bool(false,
                                    R.styleable.AndroidManifestApplication_restoreAnyVersion, sa))
                            .setFullBackupOnly(bool(false,
                                    R.styleable.AndroidManifestApplication_fullBackupOnly, sa))
                            .setBackupInForeground(bool(false,
                                    R.styleable.AndroidManifestApplication_backupInForeground, sa));
                }

                TypedValue v = sa.peekValue(
                        R.styleable.AndroidManifestApplication_fullBackupContent);
                int fullBackupContent = 0;

                if (v != null) {
                    fullBackupContent = v.resourceId;

                    if (v.resourceId == 0) {
                        if (DEBUG_BACKUP) {
                            Slog.v(TAG, "fullBackupContent specified as boolean=" +
                                    (v.data == 0 ? "false" : "true"));
                        }
                        // "false" => -1, "true" => 0
                        fullBackupContent = v.data == 0 ? -1 : 0;
                    }

                    pkg.setFullBackupContent(fullBackupContent);
                }
                if (DEBUG_BACKUP) {
                    Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName);
                }
            }

            if (sa.getBoolean(R.styleable.AndroidManifestApplication_persistent, false)) {
                // Check if persistence is based on a feature being present
                final String requiredFeature = sa.getNonResourceString(R.styleable
                        .AndroidManifestApplication_persistentWhenFeatureAvailable);
                pkg.setPersistent(requiredFeature == null || mCallback.hasFeature(requiredFeature));
            }

            if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
                pkg.setResizeableActivity(sa.getBoolean(
                        R.styleable.AndroidManifestApplication_resizeableActivity, true));
            } else {
                pkg.setResizeableActivityViaSdkVersion(
                        targetSdk >= Build.VERSION_CODES.N);
            }

            String taskAffinity;
            if (targetSdk >= Build.VERSION_CODES.FROYO) {
                taskAffinity = sa.getNonConfigurationString(
                        R.styleable.AndroidManifestApplication_taskAffinity,
                        Configuration.NATIVE_CONFIG_VERSION);
            } else {
                // Some older apps have been seen to use a resource reference
                // here that on older builds was ignored (with a warning).  We
                // need to continue to do this for them so they don't break.
                taskAffinity = sa.getNonResourceString(
                        R.styleable.AndroidManifestApplication_taskAffinity);
            }

            ParseResult<String> taskAffinityResult = ComponentParseUtils.buildTaskAffinityName(
                    pkgName, pkgName, taskAffinity, input);
            if (taskAffinityResult.isError()) {
                return input.error(taskAffinityResult);
            }

            pkg.setTaskAffinity(taskAffinityResult.getResult());
            String factory = sa.getNonResourceString(
                    R.styleable.AndroidManifestApplication_appComponentFactory);
            if (factory != null) {
                String appComponentFactory = ParsingUtils.buildClassName(pkgName, factory);
                if (appComponentFactory == null) {
                    return input.error("Empty class name in package " + pkgName);
                }

                pkg.setAppComponentFactory(appComponentFactory);
            }

            CharSequence pname;
            if (targetSdk >= Build.VERSION_CODES.FROYO) {
                pname = sa.getNonConfigurationString(
                        R.styleable.AndroidManifestApplication_process,
                        Configuration.NATIVE_CONFIG_VERSION);
            } else {
                // Some older apps have been seen to use a resource reference
                // here that on older builds was ignored (with a warning).  We
                // need to continue to do this for them so they don't break.
                pname = sa.getNonResourceString(
                        R.styleable.AndroidManifestApplication_process);
            }
            ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName(
                    pkgName, null, pname, flags, mSeparateProcesses, input);
            if (processNameResult.isError()) {
                return input.error(processNameResult);
            }

            String processName = processNameResult.getResult();
            pkg.setProcessName(processName);

            if (pkg.isCantSaveState()) {
                // A heavy-weight application can not be in a custom process.
                // We can do direct compare because we intern all strings.
                if (processName != null && !processName.equals(pkgName)) {
                    return input.error(
                            "cantSaveState applications can not use custom processes");
                }
            }

            String classLoaderName = pkg.getClassLoaderName();
            if (classLoaderName != null
                    && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
                return input.error("Invalid class loader name: " + classLoaderName);
            }

            pkg.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestApplication_gwpAsanMode, -1));
            pkg.setMemtagMode(sa.getInt(R.styleable.AndroidManifestApplication_memtagMode, -1));
            if (sa.hasValue(R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized)) {
                Boolean v = sa.getBoolean(
                        R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized, false);
                pkg.setNativeHeapZeroInitialized(
                        v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED);
            }
            if (sa.hasValue(
                    R.styleable.AndroidManifestApplication_requestRawExternalStorageAccess)) {
                pkg.setRequestRawExternalStorageAccess(sa.getBoolean(R.styleable
                                .AndroidManifestApplication_requestRawExternalStorageAccess,
                        false));
            }
            if (sa.hasValue(
                    R.styleable.AndroidManifestApplication_requestForegroundServiceExemption)) {
                pkg.setRequestForegroundServiceExemption(sa.getBoolean(R.styleable
                                .AndroidManifestApplication_requestForegroundServiceExemption,
                        false));
            }
        } finally {
            sa.recycle();
        }

        boolean hasActivityOrder = false;
        boolean hasReceiverOrder = false;
        boolean hasServiceOrder = false;
        final int depth = parser.getDepth();
        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG
                || parser.getDepth() > depth)) {
            if (type != XmlPullParser.START_TAG) {
                continue;
            }

            final ParseResult result;
            String tagName = parser.getName();
            boolean isActivity = false;
            switch (tagName) {
                case "activity":
                    isActivity = true;
                    // fall-through
                case "receiver":
                    ParseResult<ParsedActivity> activityResult =
                            ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
                                    res, parser, flags, sUseRoundIcon, input);

                    if (activityResult.isSuccess()) {
                        ParsedActivity activity = activityResult.getResult();
                        if (isActivity) {
                            hasActivityOrder |= (activity.getOrder() != 0);
                            pkg.addActivity(activity);
                        } else {
                            hasReceiverOrder |= (activity.getOrder() != 0);
                            pkg.addReceiver(activity);
                        }
                    }

                    result = activityResult;
                    break;
                case "service":
                    ParseResult<ParsedService> serviceResult =
                            ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,
                                    flags, sUseRoundIcon, input);
                    if (serviceResult.isSuccess()) {
                        ParsedService service = serviceResult.getResult();
                        hasServiceOrder |= (service.getOrder() != 0);
                        pkg.addService(service);
                    }

                    result = serviceResult;
                    break;
                case "provider":
                    ParseResult<ParsedProvider> providerResult =
                            ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
                                    flags, sUseRoundIcon, input);
                    if (providerResult.isSuccess()) {
                        pkg.addProvider(providerResult.getResult());
                    }

                    result = providerResult;
                    break;
                case "activity-alias":
                    activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,
                            parser, sUseRoundIcon, input);
                    if (activityResult.isSuccess()) {
                        ParsedActivity activity = activityResult.getResult();
                        hasActivityOrder |= (activity.getOrder() != 0);
                        pkg.addActivity(activity);
                    }

                    result = activityResult;
                    break;
                default:
                    result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags);
                    break;
            }

            if (result.isError()) {
                return input.error(result);
            }
        }

        if (TextUtils.isEmpty(pkg.getStaticSharedLibName())) {
            // Add a hidden app detail activity to normal apps which forwards user to App Details
            // page.
            ParseResult<ParsedActivity> a = generateAppDetailsHiddenActivity(input, pkg);
            if (a.isError()) {
                // Error should be impossible here, as the only failure case as of SDK R is a
                // string validation error on a constant ":app_details" string passed in by the
                // parsing code itself. For this reason, this is just a hard failure instead of
                // deferred.
                return input.error(a);
            }

            pkg.addActivity(a.getResult());
        }

        if (hasActivityOrder) {
            pkg.sortActivities();
        }
        if (hasReceiverOrder) {
            pkg.sortReceivers();
        }
        if (hasServiceOrder) {
            pkg.sortServices();
        }

        // Must be run after the entire {@link ApplicationInfo} has been fully processed and after
        // every activity info has had a chance to set it from its attributes.
        setMaxAspectRatio(pkg);
        setMinAspectRatio(pkg);
        setSupportsSizeChanges(pkg);

        pkg.setHasDomainUrls(hasDomainURLs(pkg));

        return input.success(pkg);
    }

桌面是如何展示出来的

桌面通过跨进程通信从packagemanagerService获取应用安装信息

packageManagerService 类图

ApplicationPackageManager 集成自packageManager
app通过ApplicationPackageManager 走IPackageManager.aidl走到PackageManagerService

既然桌面是跨进程获取数据,那是如何拿到图片的,总共三步 ,缓存 拿不到 -》applicationinfo ->resource

public Drawable getDrawable(String packageName, @DrawableRes int resId,
                              @Nullable ApplicationInfo appInfo) {
      //1,先看有没有缓存
      final ResourceName name = new ResourceName(packageName, resId);
      final Drawable cachedIcon = getCachedIcon(name);
      if (cachedIcon != null) {
          return cachedIcon;
      }

      //2,拿出applicationInfo
      if (appInfo == null) {
          try {
              appInfo = getApplicationInfo(packageName, sDefaultFlags);
          } catch (PackageManager.NameNotFoundException e) {
              return null;
          }
      }

      //3,通过application 拿出resource
      if (resId != 0) {
          try {
              final Resources r = getResourcesForApplication(appInfo);
              //通过resource拿出drawbale
              final Drawable dr = r.getDrawable(resId, null);
              if (dr != null) {
                  putCachedIcon(name, dr);
              }

              if (false) {
                  RuntimeException e = new RuntimeException("here");
                  e.fillInStackTrace();
                  Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resId)
                                  + " from package " + packageName
                                  + ": app scale=" + r.getCompatibilityInfo().applicationScale
                                  + ", caller scale=" + mContext.getResources()
                                  .getCompatibilityInfo().applicationScale,
                          e);
              }
              if (DEBUG_ICONS) {
                  Log.v(TAG, "Getting drawable 0x"
                          + Integer.toHexString(resId) + " from " + r
                          + ": " + dr);
              }
              return dr;
          } catch (PackageManager.NameNotFoundException e) {
              Log.w("PackageManager", "Failure retrieving resources for "
                      + appInfo.packageName);
          } catch (Resources.NotFoundException e) {
              Log.w("PackageManager", "Failure retrieving resources for "
                      + appInfo.packageName + ": " + e.getMessage());
          } catch (Exception e) {
              // If an exception was thrown, fall through to return
              // default icon.
              Log.w("PackageManager", "Failure retrieving icon 0x"
                      + Integer.toHexString(resId) + " in package "
                      + packageName, e);
          }
      }

      return null;
  }

那么又是如何拿到resource,applicationInfo 实现了Parcelable 这个看起来也不是aidl可以办到的序列化的类呀


  public Resources getResourcesForApplication(@NonNull ApplicationInfo app,
                                              @Nullable Configuration configuration) throws PackageManager.NameNotFoundException {
      //如果system 直接拿system ui 拿到
      if (app.packageName.equals("system")) {
          Context sysuiContext = mContext.mMainThread.getSystemUiContext();
          if (configuration != null) {
              sysuiContext = sysuiContext.createConfigurationContext(configuration);
          }
          return sysuiContext.getResources();
      }
      final boolean sameUid = (app.uid == Process.myUid());
      //否则这个看不懂
      final Resources r = mContext.mMainThread.getTopLevelResources(
              sameUid ? app.sourceDir : app.publicSourceDir,
              sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs,
              app.resourceDirs, app.overlayPaths, app.sharedLibraryFiles,
              mContext.mPackageInfo, configuration);
      if (r != null) {
          return r;
      }
      throw new PackageManager.NameNotFoundException("Unable to open " + app.publicSourceDir);
  }
  ```

# WorkManagerService
负责窗口添加删除,过度动画,事件传递,管理surface
# initPolicy
窗口管理策略,什么样的窗口才显示,窗口展示顺序,比如空白屏这些
# handler.runWithScissors
  ```
  public final boolean runWithScissors(final Runnable r, long timeout) {
      if (r == null) {
          throw new IllegalArgumentException("runnable must not be null");
      }
      if (timeout < 0) {
          throw new IllegalArgumentException("timeout must be non-negative");
      }

      if (Looper.myLooper() == mLooper) {
          r.run();
          return true;
      }

      BlockingRunnable br = new BlockingRunnable(r);
      return br.postAndWait(this, timeout);
  }



private static final class BlockingRunnable implements Runnable {
      private final Runnable mTask;
      private boolean mDone;

      public BlockingRunnable(Runnable task) {
          mTask = task;
      }

      @Override
      public void run() {
          try {
              mTask.run();
          } finally {
              //执行完以后唤醒wait
              synchronized (this) {
                  mDone = true;
                  notifyAll();
              }
          }
      }
      //post 以及等待当前结果执行
      public boolean postAndWait(Handler handler, long timeout) {
          if (!handler.post(this)) {
              return false;
          }

          synchronized (this) {
              if (timeout > 0) {
                  final long expirationTime = SystemClock.uptimeMillis() + timeout;
                  while (!mDone) {
                      long delay = expirationTime - SystemClock.uptimeMillis();
                      if (delay <= 0) {
                          return false; // timeout
                      }
                      try {
                          //释放锁
                          wait(delay);
                      } catch (InterruptedException ex) {
                      }
                  }
              } else {
                  //用while防止别的释放
                  while (!mDone) {
                      try {
                          //释放锁
                          wait();
                      } catch (InterruptedException ex) {
                      }
                  }
              }
          }
          return true;
      }
  }
  ```

# 看代码技巧
## 流程
1,第一遍 20分钟以内 ,看概括
2,看过程
3,看细节
5, 看支线流程

不影响流程的是直线,再不看完就结束了的是主线
没找到实现类就去前面一步

# 专业技能
必须写亮点,不然面试官乱问
研究过glide生命周期机制,三级缓存设计思想
以简历目标去学习

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容