AssetManager的释放跟踪

74 篇文章 1 订阅

AssetManager的释放跟踪

 

AssetManager的创建很容易找到,就是new AssetManager的地方,但是在java里怎么调到的finalize()方法,进而调用到C++里的AssetManager的析构方法的呢?

 

屏蔽掉以下代码

 

        boolean doPostDeleteLI(boolean delete) {

            if (DEBUG_SD_INSTALL) Slog.i(TAG, "doPostDeleteLI() del=" + delete);

            final List<String> allCodePaths = getAllCodePaths();

            boolean mounted = PackageHelper.isContainerMounted(cid);

            if (mounted) {

                // Unmount first

                if (PackageHelper.unMountSdDir(cid)) {

                    mounted = false;

                }

            }

            if (!mounted && delete) {

                cleanUpResourcesLI(allCodePaths);

            }

            return !mounted;

        }

 

让系统不发生重启

观察AssetManager的创建和释放

 

创建

05-01 09:05:20.879: I/assetCpp(19300): Creating AssetManager 0x7f678ce000 #8

05-01 09:05:20.886: W/assetCpp(19300): In 0x7f678ce000 Asset zip path: /mnt/asec/com.example.myservice-2/base.apk

 

 

中间log

05-01 09:05:28.384: D/PackageManagerService(19300): =====pms L13193,  if (!mounted && delete)

05-01 09:05:28.384: D/PackageManagerService(19300): =====pms L13198, return !mounted

05-01 09:05:28.384: D/PackageManagerService(19300): =====9  returnCode = deletePackageX(

05-01 09:05:28.384: D/PackageManagerService(19300): =====9  observer.onPackageDeleted, packageName=com.example.myservice, returnCode=1

 

 

释放

05-01 09:05:28.580: W/AssetManager(19300): AssetManager android.content.res.AssetManager@1cf2bc finalized with non-zero refs: 5

05-01 09:05:28.582: D/AssetManager(19300): =====CCAM incRefsLocked, this=android.content.res.AssetManager@e3f0648, iNum=0, mNumRefs=34

05-01 09:05:28.582: W/AssetManager(19300): Reference from here

05-01 09:05:28.592: W/assetJNI(19300): =====jni Destroying AssetManager 0x7f678ce000 for Java object 0x7f88447ef4

05-01 09:05:28.592: W/assetJNI(19300): =====jni L2178   delete am; am=0x7f678ce000

 

当不重启的时候,在deletePackageX后的一段时间内,AssetManager进行了释放

 

通过和发生重启时的log进行对比,发现正常释放的log里有

05-02 04:21:22.871: I/ActivityManager(18460): Force stopping com.UCMobile appid=10148 user=0: pkg removed

ams里查找pkg removed

 

查找,得到是private final boolean forceStopPackageLocked(String packageName, int appId,

里进行的打印,增加堆栈打印log

进行查看,得到其调用堆栈

 

05-02 04:21:22.871: V/ActivityManager(18460): Broadcast: Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:com.UCMobile flg=0x4000010 (has extras) } ordered=false userid=0 callerApp=null

05-02 04:21:22.871: D/ActivityManager(18460): =====ams, forceStopPackageLocked

05-02 04:21:22.871: D/ActivityManager(18460): ===== begin =====

05-02 04:21:22.871: D/ActivityManager(18460): com.android.server.am.ActivityManagerService.forceStopPackageLocked(ActivityManagerService.java:6531)

05-02 04:21:22.871: D/ActivityManager(18460): com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:18084)

05-02 04:21:22.871: D/ActivityManager(18460): com.android.server.am.ActivityManagerService.broadcastIntent(ActivityManagerService.java:18463)

05-02 04:21:22.871: D/ActivityManager(18460): com.android.server.pm.PackageManagerService$9.run(PackageManagerService.java:11070)

05-02 04:21:22.871: D/ActivityManager(18460): android.os.Handler.handleCallback(Handler.java:815)

05-02 04:21:22.871: D/ActivityManager(18460): android.os.Handler.dispatchMessage(Handler.java:104)

05-02 04:21:22.871: D/ActivityManager(18460): android.os.Looper.loop(Looper.java:207)

05-02 04:21:22.871: D/ActivityManager(18460): android.os.HandlerThread.run(HandlerThread.java:61)

05-02 04:21:22.871: D/ActivityManager(18460): com.android.server.ServiceThread.run(ServiceThread.java:46)

05-02 04:21:22.871: I/ActivityManager(18460): Force stopping com.UCMobile appid=10148 user=0: pkg removed

 

 

boolean doPostDeleteLI(boolean delete)里进行sleep操作,来验证是否是由于vold里处理的太快,而导致AMS里来不及释放导致的重启,结果发现无论sleep多久,都会发生重启,而且log中没有

I/ActivityManager(18460): Force stopping com.UCMobile appid=10148 user=0: pkg removed

 

根据调用堆栈里的

05-02 04:21:22.871: D/ActivityManager(18460): com.android.server.pm.PackageManagerService$9.run(PackageManagerService.java:11070)

 

找到

pms

11070

                        am.broadcastIntent(null, intent, null, finishedReceiver,

                                0, null, null, null, android.app.AppOpsManager.OP_NONE,

                                null, finishedReceiver != null, false, id);

pms的方法sendPackageBroadcast

        // Modified for ThemeManager

    final void sendPackageBroadcast(final String action, final String pkg,

            final String intentCategory, final Bundle extras, final String targetPkg,

            final IIntentReceiver finishedReceiver, final int[] userIds) {

        mHandler.post(new Runnable() {

            @Override

            public void run() {

 

 

也就是说,sendPackageBroadcast没有及时执行,一直在等待。

注意到,是采用mHandler.post(new Runnable()的方式执行的,再查看卸载流程

 

public void deletePackage

 

        // Queue up an async operation since the package deletion may take a little while.

        mHandler.post(new Runnable() {

            public void run() {

                mHandler.removeCallbacks(this);

                final int returnCode = deletePackageX(packageName, userId, flags);

                if (observer != null) {

                    try {

                        observer.onPackageDeleted(packageName, returnCode, null);

                    } catch (RemoteException e) {

                        Log.i(TAG, "Observer no longer exists.");

                    } //end catch

                } //end if

            } //end run

        });

 

使用了同一个mHandler,所以sendPackageBroadcast里的处理一直要等待deletePackageX操作完成才会开始执行,所以之前的sleep无效

 

查看L的代码,在final void sendPackageBroadcast(final String action, final String pkg里没有使用mHandler.post(new Runnable()去执行,

屏蔽掉mHandler.post(new Runnable()后,可以正常卸载SD卡里的应用了

 

 

sendPackageBroadcast是在deletePackageX方法里的

        if (res) {

            info.sendBroadcast(true, systemUpdate, removedForAllUsers);

调用的

 

 

 

接着查看AMS里做了怎样的操作进行了释放

 

 

6. forceStopPackageLocked

查看AMS中的   private final boolean forceStopPackageLocked(String packageName, int appId,

方法

 

……

 

        if (doit) {

            if (purgeCache && packageName != null) {

                AttributeCache ac = AttributeCache.instance();

                if (ac != null) {

                    ac.removePackage(packageName);

                }

            }

            if (mBooted) {

                mStackSupervisor.resumeTopActivitiesLocked();

                mStackSupervisor.scheduleIdleLocked();

            }

        }

 

        return didSomething;

    }

 

 

 

 

 

点击一个应用的时候,会加载其对应的base.apk,其调用堆栈为

05-02 04:21:12.863: D/AssetManager(18460): android.content.res.AssetManager.addAssetPath(AssetManager.java:653)

05-02 04:21:12.863: D/AssetManager(18460): android.app.ResourcesManager.getTopLevelResources(ResourcesManager.java:221)

05-02 04:21:12.863: D/AssetManager(18460): android.app.ActivityThread.getTopLevelResources(ActivityThread.java:1854)

05-02 04:21:12.863: D/AssetManager(18460): android.app.LoadedApk.getResources(LoadedApk.java:558)

05-02 04:21:12.863: D/AssetManager(18460):

        Resources resources = packageInfo.getResources(mainThread);

android.app.ContextImpl.<init>(ContextImpl.java:1884)

05-02 04:21:12.863: D/AssetManager(18460): android.app.ContextImpl.createPackageContextAsUser(ContextImpl.java:1733)

05-02 04:21:12.863: D/AssetManager(18460): android.app.ContextImpl.createPackageContextAsUser(ContextImpl.java:1718)

05-02 04:21:12.863: D/AssetManager(18460): com.android.server.AttributeCache.get(AttributeCache.java:114)

05-02 04:21:12.863: D/AssetManager(18460):

  AttributeCache.Entry ent = AttributeCache.instance().get(packageName, com.android.server.am.ActivityRecord.<init>(ActivityRecord.java:564)

05-02 04:21:12.863: D/AssetManager(18460):

ActivityRecord r = new ActivityRecord(

com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1763)

05-02 04:21:12.863: D/AssetManager(18460): com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1153)

05-02 04:21:12.863: D/AssetManager(18460): com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4271)

05-02 04:21:12.863: D/AssetManager(18460): com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:4258)

05-02 04:21:12.863: D/AssetManager(18460): android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:168)

05-02 04:21:12.863: D/AssetManager(18460): com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2703)

 

AttributeCache

查看

AttributeCache

 

    public Entry get(String packageName, int resId, int[] styleable, int userId) {

        synchronized (this) {

            Package pkg = mPackages.get(packageName);

            HashMap<int[], Entry> map = null;

            Entry ent = null;

            if (pkg != null) {

                map = pkg.mMap.get(resId);

                if (map != null) {

                    ent = map.get(styleable);

                    if (ent != null) {

                        return ent;

                    }

                }

            } else {

                Context context;

                try {

                    context = mContext.createPackageContextAsUser(packageName, 0,

                            new UserHandle(userId));

                    if (context == null) {

                        return null;

                    }

                } catch (PackageManager.NameNotFoundException e) {

                    return null;

                }

                pkg = new Package(context);

                mPackages.put(packageName, pkg);

            }

           

            if (map == null) {

                map = new HashMap<int[], Entry>();

                pkg.mMap.put(resId, map);

            }

           

            try {

                ent = new Entry(pkg.context,

                        pkg.context.obtainStyledAttributes(resId, styleable));

                map.put(styleable, ent);

            } catch (Resources.NotFoundException e) {

                return null;

            }

           

            return ent;

        }

    }

}

 

 

AssetManager的创建可以追溯到这里,

private final boolean forceStopPackageLocked(String packageName, int appId,

里起释放作用的是

                AttributeCache ac = AttributeCache.instance();

                if (ac != null) {

                    ac.removePackage(packageName);

                }

 

AttributeCache

    public void removePackage(String packageName) {

        synchronized (this) {

            mPackages.remove(packageName);

        }

    }

 

 

    private final WeakHashMap<String, Package> mPackages =

            new WeakHashMap<String, Package>();

 

7. 另外一种解决尝试

AttributeCache使用了一个单例

                AttributeCache ac = AttributeCache.instance();

                if (ac != null) {

                    ac.removePackage(packageName);

                }

 

添加到PMS里的

 

        boolean doPostDeleteLI(boolean delete) {

            if (DEBUG_SD_INSTALL) Slog.i(TAG, "doPostDeleteLI() del=" + delete);

            final List<String> allCodePaths = getAllCodePaths();

            boolean mounted = PackageHelper.isContainerMounted(cid);

            if (mounted) {

                // Unmount first

                if (PackageHelper.unMountSdDir(cid)) {

                    mounted = false;

                }

            }

            if (!mounted && delete) {

                cleanUpResourcesLI(allCodePaths);

            }

            return !mounted;

        }

 

 

                int pos = cid.lastIndexOf("-");

                if (pos > 0)

                {

                        String packageName = cid.substring(0, pos);

                         AttributeCache ac = AttributeCache.instance();

                         if (ac != null) {

                                Slog.d(TAG, "=====927,  if (ac != null), ac.removePackage(packageName), " + packageName);

                            ac.removePackage(packageName);

                         }

 

                        //System.out.println("newString=" + newString);

                }

                else

                {

                        Slog.d(TAG, "=====927, not find -");

                }

        }

 

进行验证,这样方法是可行的。

 

优化

使用INSTALL_PACKAGE_SUFFIX代替"-"

    // Suffix used during package installation when copying/moving

    // package apks to install directory.

    private static final String INSTALL_PACKAGE_SUFFIX = "-";

 

 

 


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值