安装应用手机内部存储不足时弹框流程

安装应用时,手机内部存储空间不足的弹框流程:

1.手机内部存储空间阈值为500M:

StorageManager.java中:

    /**
     * Return the number of available bytes at which the given path is
     * considered running low on storage.
     *
     * @hide
     */
    public long getStorageLowBytes(File path) {
        final long lowPercent = Settings.Global.getInt(mResolver,
                Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
        final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;

        final long maxLowBytes = Settings.Global.getLong(mResolver,
                Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);

        return Math.min(lowBytes, maxLowBytes);
    }

2.在PackageInstaller中,在InstallInstalling.java的OnCreate中会进行一次getAllocatableBytes与file.length()的判断,以免在session.openWrite的时候抛出异常:

11-02 05:00:43.684  3993  4022 E InstallInstalling: Could not write package
11-02 05:00:43.684  3993  4022 E InstallInstalling: java.io.IOException: Failed to allocate 62778401 because only 0 allocatable
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at java.lang.reflect.Constructor.newInstance0(Native Method)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.os.ParcelableException.readFromParcel(ParcelableException.java:56)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.os.ParcelableException$1.createFromParcel(ParcelableException.java:82)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.os.ParcelableException$1.createFromParcel(ParcelableException.java:79)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.os.Parcel.readParcelable(Parcel.java:2774)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.os.Parcel.createException(Parcel.java:1945)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.os.Parcel.readException(Parcel.java:1918)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.os.Parcel.readException(Parcel.java:1868)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.content.pm.IPackageInstallerSession$Stub$Proxy.openWrite(IPackageInstallerSession.java:256)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.content.pm.PackageInstaller$Session.openWrite(PackageInstaller.java:839)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at com.android.packageinstaller.InstallInstalling$InstallingAsyncTask.doInBackground(InstallInstalling.java:347)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at com.android.packageinstaller.InstallInstalling$InstallingAsyncTask.doInBackground(InstallInstalling.java:326)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.os.AsyncTask$2.call(AsyncTask.java:333)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at java.lang.Thread.run(Thread.java:764)
11-02 05:00:43.684  3993  4022 E InstallInstalling: Caused by: android.os.RemoteException: Remote stack trace:
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.util.ExceptionUtils.wrap(ExceptionUtils.java:34)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at com.android.server.pm.PackageInstallerSession.openWrite(PackageInstallerSession.java:630)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.content.pm.IPackageInstallerSession$Stub.onTransact(IPackageInstallerSession.java:82)
11-02 05:00:43.684  3993  4022 E InstallInstalling: 	at android.os.Binder.execTransact(Binder.java:731)

因为openWrite是调用的PackageInstallerSession中openWrite,openWrite调用doWriteInternal,doWriteInternal会调用:

mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
                        PackageHelper.translateAllocateFlags(params.installFlags));

在StorageManager中allocateBytes的时候,实际调用的是StorageManagerService的allocateBytes:

    @Override
    public void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) {
        flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);

        final long allocatableBytes = getAllocatableBytes(volumeUuid, flags, callingPackage);
        if (bytes > allocatableBytes) {
            throw new ParcelableException(new IOException("Failed to allocate " + bytes
                    + " because only " + allocatableBytes + " allocatable"));
        }

        final StorageManager storage = mContext.getSystemService(StorageManager.class);
        final long token = Binder.clearCallingIdentity();
        try {
            // Free up enough disk space to satisfy both the requested allocation
            // and our low disk warning space.
            final File path = storage.findPathForUuid(volumeUuid);
            if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
                bytes += storage.getStorageFullBytes(path);
            } else {
                bytes += storage.getStorageLowBytes(path);
            }

            mPms.freeStorage(volumeUuid, bytes, flags);
        } catch (IOException e) {
            throw new ParcelableException(e);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

当申请的bytes大于getAllocatableBytes时,则抛出异常:

if (bytes > allocatableBytes) {
    throw new ParcelableException(new IOException("Failed to allocate " + bytes
                 + " because only " + allocatableBytes + " allocatable"));
}

所以在进行openWrite前,判断当前申请的bytes是否大于getAllocatableBytes,如果大于,则安装失败,发送:

//mq.zhang add begin
//Add by mq.zhang,20190826,bug 5129,for show out of space dialog if needed
long sizeBytes = file.length();
//Calculate freeing disk space on the target device
long allocatableBytes = 0;
StorageManager storage =  mContext.getSystemService(StorageManager.class);
//long lowThreshold = storage.getStorageLowBytes(Environment.getDataDirectory()); //得到手机内部存储空间阈值
List<VolumeInfo> volumes = storage.getVolumes();
for (VolumeInfo vol : volumes) {
    if (vol.getType() == VolumeInfo.TYPE_PRIVATE) {
        //StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
        //freeBytes = stats.getFreeBytes(vol.getFsUuid()); //得到手机内部存储剩余空间
        allocatableBytes = storage.getAllocatableBytes(StorageManager.convert(vol.getFsUuid()));
    }
}
if (sizeBytes >= allocatableBytes) {
    launchFailure(PackageInstaller.STATUS_FAILURE_STORAGE, null);
}
//mq.zhang add end

3.openWrite进行申请bytes成功后,在安装过程中还会由于copyApk的时候没有空间导致安装失败,发送:PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE

    /**
     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
     * if the package manager service found that the device didn't have enough storage space to
     * install the app.
     *
     * @hide
     */
    @SystemApi
    public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;

4.在InstallFailed.java中,当收到legacyStatus为以下两种时,弹出空间不足弹框:
PackageInstaller.STATUS_FAILURE_STORAGE
PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE

//mq.zhang add begin
//Add by mq.zhang,20190826,bug 5129,for show out of space dialog if needed
int legacyStatus = getIntent().getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS,PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
if (legacyStatus == PackageInstaller.STATUS_FAILURE_STORAGE
            || legacyStatus == PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE) {
    (new OutOfSpaceDialog()).show(getFragmentManager(), "outofspace");
}
//mq.zhang add end

    /**
       * Dialog shown when we ran out of space during installation. This contains a link to the
       * "manage applications" settings page.
       */
    public static class OutOfSpaceDialog extends DialogFragment {
        private InstallFailed mActivity;

        @Override
        public void onAttach(Context context) {
            super.onAttach(context);

            mActivity = (InstallFailed) context;
        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            return new AlertDialog.Builder(mActivity)
                    .setTitle(R.string.out_of_space_dlg_title)
                    .setMessage(getString(R.string.out_of_space_dlg_text, mActivity.mLabel))
                    .setPositiveButton(R.string.manage_applications, (dialog, which) -> {
                        // launch manage applications
                        Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE");
                        startActivity(intent);
                        mActivity.finish();
                    })
                    .setNegativeButton(R.string.cancel, (dialog, which) -> mActivity.finish())
                    .create();
        }

        @Override
        public void onCancel(DialogInterface dialog) {
            super.onCancel(dialog);

            mActivity.finish();
        }
    }

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值