Rk3399 Android9.0 恢复出厂设置流程

2023-11-03

Reset 流程 :

1.原生设置中响应 恢复出厂设置 功能,继而发出重置广播(Intent.ACTION_FACTORY_RESET) .

2.frameWork层 接收到此广播,根据广播所携带的参数执行Android层的Reset设定.

3.Android层执行到最后会将Reset配置信息写入 /cache/recovery/command 中,最终进入Recover.

Reset 逻辑流程图:

 图片来源 : https://blog.csdn.net/qq_34787560/article/details/89226050

Reset 代码追踪:

1.UI界面点击:

packages/apps/Settings/src/com/android/settings/MasterClearConfirm.java

    private void doMasterClear() {
        Intent intent = new Intent(Intent.ACTION_FACTORY_RESET);
        intent.setPackage("android");
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        intent.putExtra(Intent.EXTRA_REASON, "MasterClearConfirm");
        intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, mEraseSdCard);
        intent.putExtra(Intent.EXTRA_WIPE_ESIMS, mEraseEsims);
        getActivity().sendBroadcast(intent);
        // Intent handling is asynchronous -- assume it will happen soon.
    }

在此注意,广播需要携带的参数.

2.framework接收 Reset 广播 (Intent.ACTION_FACTORY_RESET)

在Android 源码中,有对Intent的封装如下.

/**
     * A broadcast action to trigger a factory reset.
     *
     * <p>The sender must hold the {@link android.Manifest.permission#MASTER_CLEAR} permission. The
     * reason for the factory reset should be specified as {@link #EXTRA_REASON}.
     *
     * <p>Not for use by third-party applications.
     *
     * @see #EXTRA_FORCE_FACTORY_RESET
     *
     * {@hide}
     */
    @SystemApi
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_FACTORY_RESET = "android.intent.action.FACTORY_RESET";

在 framework/base/core/res/AndroidManifest.xml 中声明 MasterClearReceiver .java静态接收 Reset 广播.

        <receiver android:name="com.android.server.MasterClearReceiver"
            android:permission="android.permission.MASTER_CLEAR">
            <intent-filter
                    android:priority="100" >
                <!-- For Checkin, Settings, etc.: action=FACTORY_RESET -->
                <action android:name="android.intent.action.FACTORY_RESET" />
                <!-- As above until all the references to the deprecated MASTER_CLEAR get updated to
                     FACTORY_RESET. -->
                <action android:name="android.intent.action.MASTER_CLEAR" />

                <!-- MCS always uses REMOTE_INTENT: category=MASTER_CLEAR -->
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="android.intent.category.MASTER_CLEAR" />
            </intent-filter>
        </receiver>

3.在 MasterClearReceiver .java 执行 onReceive() 方法

framework/base/services/core/java/com/android/server/MasterClearReceiver .java

    @Override
    public void onReceive(final Context context, final Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
            if (!"google.com".equals(intent.getStringExtra("from"))) {
                Slog.w(TAG, "Ignoring master clear request -- not from trusted server.");
                return;
            }
        }
        if (Intent.ACTION_MASTER_CLEAR.equals(intent.getAction())) {
            Slog.w(TAG, "The request uses the deprecated Intent#ACTION_MASTER_CLEAR, "
                    + "Intent#ACTION_FACTORY_RESET should be used instead.");
        }
        if (intent.hasExtra(Intent.EXTRA_FORCE_MASTER_CLEAR)) {
            Slog.w(TAG, "The request uses the deprecated Intent#EXTRA_FORCE_MASTER_CLEAR, "
                    + "Intent#EXTRA_FORCE_FACTORY_RESET should be used instead.");
        }

        final boolean shutdown = intent.getBooleanExtra("shutdown", false);
        final String reason = intent.getStringExtra(Intent.EXTRA_REASON);
        mWipeExternalStorage = intent.getBooleanExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, false);
        mWipeEsims = intent.getBooleanExtra(Intent.EXTRA_WIPE_ESIMS, false);
        final boolean forceWipe = intent.getBooleanExtra(Intent.EXTRA_FORCE_MASTER_CLEAR, false)
                || intent.getBooleanExtra(Intent.EXTRA_FORCE_FACTORY_RESET, false);

        Slog.w(TAG, "!!! FACTORY RESET !!!");
        // The reboot call is blocking, so we need to do it on another thread.
        Thread thr = new Thread("Reboot") {
            @Override
            public void run() {
                try {
                    RecoverySystem
                            .rebootWipeUserData(context, shutdown, reason, forceWipe, mWipeEsims);
                    Log.wtf(TAG, "Still running after master clear?!");
                } catch (IOException e) {
                    Slog.e(TAG, "Can't perform master clear/factory reset", e);
                } catch (SecurityException e) {
                    Slog.e(TAG, "Can't perform master clear/factory reset", e);
                }
            }
        };

        if (mWipeExternalStorage || mWipeEsims) {
            // thr will be started at the end of this task.
            new WipeDataTask(context, thr).execute();
        } else {
            thr.start();
        }
    }

重点有 run() 方法里的 

1.RecoverySystem .rebootWipeUserData(context, shutdown, reason, forceWipe, mWipeEsims);

2.new WipeDataTask(context, thr).execute();

第一个方法是百分百会被执行到的,是 Reset 的必经之地,稍后分析.

第二个是在发广播时 携带进来的参数.

        intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, mEraseSdCard);
        intent.putExtra(Intent.EXTRA_WIPE_ESIMS, mEraseEsims);

当任意一个参数 为 true 时,即会执行以下代码,清空 data 分区.

    private class WipeDataTask extends AsyncTask<Void, Void, Void> {
        private final Thread mChainedTask;
        private final Context mContext;
        private final ProgressDialog mProgressDialog;

        public WipeDataTask(Context context, Thread chainedTask) {
            mContext = context;
            mChainedTask = chainedTask;
            mProgressDialog = new ProgressDialog(context);
        }

        @Override
        protected void onPreExecute() {
            mProgressDialog.setIndeterminate(true);
            mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
            mProgressDialog.setMessage(mContext.getText(R.string.progress_erasing));
            mProgressDialog.show();
        }

        @Override
        protected Void doInBackground(Void... params) {
            Slog.w(TAG, "Wiping adoptable disks");
            if (mWipeExternalStorage) {
                StorageManager sm = (StorageManager) mContext.getSystemService(
                        Context.STORAGE_SERVICE);
                sm.wipeAdoptableDisks();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            mProgressDialog.dismiss();
            mChainedTask.start();
        }

    }

4. RecoverySystem.java 中的 rebootWipeUserData() 方法

frameworks/base/core/java/android/os/RecoverySystem.java

    /**
     * Reboots the device and wipes the user data and cache
     * partitions.  This is sometimes called a "factory reset", which
     * is something of a misnomer because the system partition is not
     * restored to its factory state.  Requires the
     * {@link android.Manifest.permission#REBOOT} permission.
     *
     * @param context   the Context to use
     * @param shutdown  if true, the device will be powered down after
     *                  the wipe completes, rather than being rebooted
     *                  back to the regular system.
     * @param reason    the reason for the wipe that is visible in the logs
     * @param force     whether the {@link UserManager.DISALLOW_FACTORY_RESET} user restriction
     *                  should be ignored
     * @param wipeEuicc whether wipe the euicc data
     *
     * @throws IOException  if writing the recovery command file
     * fails, or if the reboot itself fails.
     * @throws SecurityException if the current user is not allowed to wipe data.
     *
     * @hide
     */
    public static void rebootWipeUserData(Context context, boolean shutdown, String reason,
            boolean force, boolean wipeEuicc) throws IOException {
        UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
        if (!force && um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
            throw new SecurityException("Wiping data is not allowed for this user.");
        }
        final ConditionVariable condition = new ConditionVariable();

        Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        context.sendOrderedBroadcastAsUser(intent, UserHandle.SYSTEM,
                android.Manifest.permission.MASTER_CLEAR,
                new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        condition.open();
                    }
                }, null, 0, null, null);

        // Block until the ordered broadcast has completed.
        condition.block();

        if (wipeEuicc) {
            wipeEuiccData(context, PACKAGE_NAME_WIPING_EUICC_DATA_CALLBACK);
        }

        String shutdownArg = null;
        if (shutdown) {
            shutdownArg = "--shutdown_after";
        }

        String reasonArg = null;
        if (!TextUtils.isEmpty(reason)) {
            reasonArg = "--reason=" + sanitizeArg(reason);
        }

        final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() ;
        bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
    }

final ConditionVariable condition = new ConditionVariable();

Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");

 在 rebootWipeUserData() 中 开启了 ConditionVariable 锁,并且发送了 android.intent.action.MASTER_CLEAR_NOTIFICATION 这条广播,是为了在 Reset 时,可以将系统内APP的数据清除,在清除完APP数据后,再将锁关闭.

最后针对传入的不同的值,拟定好 Reset 用到的 string 变量,最终将所有参数传给当前类中的

bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);

    /**
     * Reboot into the recovery system with the supplied argument.
     * @param args to pass to the recovery utility.
     * @throws IOException if something goes wrong.
     */
    private static void bootCommand(Context context, String... args) throws IOException {
        LOG_FILE.delete();

        StringBuilder command = new StringBuilder();
        for (String arg : args) {
            if (!TextUtils.isEmpty(arg)) {
                command.append(arg);
                command.append("\n");
            }
        }

        // Write the command into BCB (bootloader control block) and boot from
        // there. Will not return unless failed.
        RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
        rs.rebootRecoveryWithCommand(command.toString());

        throw new IOException("Reboot failed (no permissions?)");
    }

此处将所有的 Reset 参数拼接起来.调用 rebootRecoveryWithCommand();

    /**
     * Talks to RecoverySystemService via Binder to set up the BCB command and
     * reboot into recovery accordingly.
     */
    private void rebootRecoveryWithCommand(String command) {
        try {
            mService.rebootRecoveryWithCommand(command);
        } catch (RemoteException ignored) {
        }
    }

    private final IRecoverySystem mService;

 在 RecoverySystem.java 文件中, mService 使用的是 IRecoverySystem.java 的实现类.

5. RecoverySystemService.java 继承 IRecoverySystem

 frameworks/base/services/core/java/com/android/server/RecoverySystemService.java

        @Override // Binder call
        public void rebootRecoveryWithCommand(String command) {
            if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
            synchronized (sRequestLock) {
                if (!setupOrClearBcb(true, command)) {
                    return;
                }

                // Having set up the BCB, go ahead and reboot.
                PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
                pm.reboot(PowerManager.REBOOT_RECOVERY);
            }
        }

 frameworks\base\core\java\android\os\PowerManager.java

    /**
     * Reboot the device.  Will not return if the reboot is successful.
     * <p>
     * Requires the {@link android.Manifest.permission#REBOOT} permission.
     * </p>
     *
     * @param reason code to pass to the kernel (e.g., "recovery") to
     *               request special boot modes, or null.
     */
    public void reboot(String reason) {
        try {
            mService.reboot(false, reason, true);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

final IPowerManager mService;

 frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java

        /**
         * Reboots the device.
         *
         * @param confirm If true, shows a reboot confirmation dialog.
         * @param reason The reason for the reboot, or null if none.
         * @param wait If true, this call waits for the reboot to complete and does not return.
         */
        @Override // Binder call
        public void reboot(boolean confirm, String reason, boolean wait) {
            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
            if (PowerManager.REBOOT_RECOVERY.equals(reason)
                    || PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
                mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
            }

            final long ident = Binder.clearCallingIdentity();
            try {
                shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
            final String reason, boolean wait) {
        if (mHandler == null || !mSystemReady) {
            if (RescueParty.isAttemptingFactoryReset()) {
                // If we're stuck in a really low-level reboot loop, and a
                // rescue party is trying to prompt the user for a factory data
                // reset, we must GET TO DA CHOPPA!
                PowerManagerService.lowLevelReboot(reason);
            } else {
                throw new IllegalStateException("Too early to call shutdown() or reboot()");
            }
        }

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
                        ShutdownThread.rebootSafeMode(getUiContext(), confirm);
                    } else if (haltMode == HALT_MODE_REBOOT) {
                        ShutdownThread.reboot(getUiContext(), reason, confirm);
                    } else {
                        ShutdownThread.shutdown(getUiContext(), reason, confirm);
                    }
                }
            }
        };


      
        // 省略部分代码,以下是代码调用的地方
        



    private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
            final String reason, boolean wait) {
        if (mHandler == null || !mSystemReady) {
            if (RescueParty.isAttemptingFactoryReset()) {
                // If we're stuck in a really low-level reboot loop, and a
                // rescue party is trying to prompt the user for a factory data
                // reset, we must GET TO DA CHOPPA!
                PowerManagerService.lowLevelReboot(reason);
            } else {
                throw new IllegalStateException("Too early to call shutdown() or reboot()");
            }
        }

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
                        ShutdownThread.rebootSafeMode(getUiContext(), confirm);
                    } else if (haltMode == HALT_MODE_REBOOT) {
                        ShutdownThread.reboot(getUiContext(), reason, confirm);
                    } else {
                        ShutdownThread.shutdown(getUiContext(), reason, confirm);
                    }
                }
            }
        };

 frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java

    /**
     * Request a clean shutdown, waiting for subsystems to clean up their
     * state etc.  Must be called from a Looper thread in which its UI
     * is shown.
     *
     * @param context Context used to display the shutdown progress dialog. This must be a context
     *                suitable for displaying UI (aka Themable).
     * @param reason code to pass to the kernel (e.g. "recovery"), or null.
     * @param confirm true if user confirmation is needed before shutting down.
     */
    public static void reboot(final Context context, String reason, boolean confirm) {
        mReboot = true;
        mRebootSafeMode = false;
        mRebootHasProgressBar = false;
        mReason = reason;
        shutdownInner(context, confirm);
    }



    // 省略部分代码,以下为调用部分


    private static void shutdownInner(final Context context, boolean confirm) {
        // ShutdownThread is called from many places, so best to verify here that the context passed
        // in is themed.
        context.assertRuntimeOverlayThemable();

        // ensure that only one thread is trying to power down.
        // any additional calls are just returned
        synchronized (sIsStartedGuard) {
            if (sIsStarted) {
                Log.d(TAG, "Request to shutdown already running, returning.");
                return;
            }
        }

        final int longPressBehavior = context.getResources().getInteger(
                        com.android.internal.R.integer.config_longPressOnPowerBehavior);
        final int resourceId = mRebootSafeMode
                ? com.android.internal.R.string.reboot_safemode_confirm
                : (longPressBehavior == 2
                        ? com.android.internal.R.string.shutdown_confirm_question
                        : com.android.internal.R.string.shutdown_confirm);

        Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);

        if (confirm) {
            final CloseDialogReceiver closer = new CloseDialogReceiver(context);
            if (sConfirmDialog != null) {
                sConfirmDialog.dismiss();
            }
            sConfirmDialog = new AlertDialog.Builder(context)
                    .setTitle(mRebootSafeMode
                            ? com.android.internal.R.string.reboot_safemode_title
                            : com.android.internal.R.string.power_off)
                    .setMessage(resourceId)
                    .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            beginShutdownSequence(context);
                        }
                    })
                    .setNegativeButton(com.android.internal.R.string.no, null)
                    .create();
            closer.dialog = sConfirmDialog;
            sConfirmDialog.setOnDismissListener(closer);
            sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
            sConfirmDialog.show();
        } else {
            beginShutdownSequence(context);
        }
    }


    // 省略部分代码,以下为调用部分


    private static void beginShutdownSequence(Context context) {
        synchronized (sIsStartedGuard) {
            if (sIsStarted) {
                Log.d(TAG, "Shutdown sequence already running, returning.");
                return;
            }
            sIsStarted = true;
        }

        sInstance.mProgressDialog = showShutdownDialog(context);
        sInstance.mContext = context;
        sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);

        // make sure we never fall asleep again
        sInstance.mCpuWakeLock = null;
        try {
            sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
                    PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
            sInstance.mCpuWakeLock.setReferenceCounted(false);
            sInstance.mCpuWakeLock.acquire();
        } catch (SecurityException e) {
            Log.w(TAG, "No permission to acquire wake lock", e);
            sInstance.mCpuWakeLock = null;
        }

        // also make sure the screen stays on for better user experience
        sInstance.mScreenWakeLock = null;
        if (sInstance.mPowerManager.isScreenOn()) {
            try {
                sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
                        PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
                sInstance.mScreenWakeLock.setReferenceCounted(false);
                sInstance.mScreenWakeLock.acquire();
            } catch (SecurityException e) {
                Log.w(TAG, "No permission to acquire wake lock", e);
                sInstance.mScreenWakeLock = null;
            }
        }

        if (SecurityLog.isLoggingEnabled()) {
            SecurityLog.writeEvent(SecurityLog.TAG_OS_SHUTDOWN);
        }

        // start the thread that initiates shutdown
        sInstance.mHandler = new Handler() {
        };
        sInstance.start();
    }

三:Factory Reset 恢复出厂设置

1. 用户选择“恢复出厂设置”
2. 设置系统将“--wipe_data”命令写入 /cache/recovery/command
3. 系统重启,并进入recovery模式 (sbin/recovery  or /system/bin/recovery)
4. recovery get_args() 将“boot-recovery”和“--wipe_data”写入BCB
5. erase_root 格式化DATA 分区
6. erase_root 格式化CACHE 分区
7. finish_recovery 擦除BCB分区
8. 重启系统

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Rk3399 Android9.0 恢复出厂设置流程 的相关文章

  • 从队列更新活动的最佳方法

    我有一个LinkedBlockingQueue在我的 生产者 调解者 消费者 模型中的调解者中 Producer 首先更新将 Mediator 添加到 ActivityQueue 中 接下来 消费者 活动在队列中等待 侦听并获取下一个项目
  • 生产中偶尔会发生 android.webkit.WebView 类膨胀错误

    我的应用程序在 Google Play 上 它在大多数设备 数千个用户 上运行良好 但在极少数情况下 占每日活跃用户百分比的一小部分 我得到Error inflating class android webkit WebView当我为我的片
  • 如何使用gradle这样的格式更改apk名称?

    当我使用 gradle 构建应用程序时 我想将 app release apk 文件名更改为如下所示 format appname of package name V version code yyMMdd R T explain appn
  • Android中如何将文件写入raw文件夹?

    我认为这是一个非常基本的问题 我目前正在编写这样的文件 File output new File exampleout mid 现在 我想将文件写入 myproject res raw 我读到我可以通过将完整的网址放在 中来做到这一点 但
  • 通过我的应用程序以编程方式插入新联系人,而不使用 Intent

    我正在使用一个应用程序 与手机联系人进行交互 我想将新联系人添加到我的手机联系人列表中 我已经尝试过以下代码 但它不起作用 void addContact Context ctx PreviewContactModel model Arra
  • Android/Java 创建辅助类来创建图表

    Goal 创建用于图形生成的辅助类 背景 我有 3 个片段 每个片段收集一些传感器数据 加速度计 陀螺仪 旋转 并使用 GraphView 绘制图表 以下是其中一个片段的代码 该代码当前工作正常 public class Gyroscope
  • 无法找到/下载 AppCompat-v7:23.1.1

    怎么了 我遇到了很多 找不到 appcompat v7 23 1 1 的问题 许多解决方案都不起作用 经过几个小时的思考和寻找答案 我遇到了一个奇怪的问题 I have gotAndroid 支持库 23 1 1 已安装 所有功能 exce
  • 调试 Java InterruptedException,即查找原因

    在调试Android应用程序时 有时中断异常发生并使应用程序崩溃 我已经能够在默认异常处理程序上设置断点 但调用堆栈不提供信息 at java util concurrent locks AbstractQueuedSynchronizer
  • 无论如何,要控制宋何时选择Android.bp,何时不选择?

    使用新的构建系统 即 Soong 安卓取代Android mk with Android bp 还有 Android Q 及以上版本 Soong将选择所有Android bp文件 无论所有文件都存在于何处 早些时候 对于 2 级和 3 级模
  • Android 导航回到 Activity;不要重新加载父级

    我有一个场景 我单击 ListFragment 并启动一个新的 Activity 如下所示 public void onListItemClick ListView l View v int position long id super o
  • 如何找到特定路线上两点之间的距离?

    我正在为我的大学开发一个 Android 应用程序 可以帮助学生跟踪大学巴士的当前位置 并为他们提供巴士到达他们的预计时间 截至目前 我获取了公交车的当前位置 通过公交车上的设备 和学生的位置 我陷入了必须找到两个 GPS 坐标之间的距离的
  • 当编辑文本获得焦点时更改边框颜色

    我想知道当编辑文本聚焦时如何更改它的边框颜色 目前它看起来像这样 我尝试过在SDK中检查源图片 但我无法理解它 我也尝试过使用xml 但无法仅更改边框颜色 如果我找到源图片 我可以在 Photoshop 中编辑以更改颜色 有什么关于如何执行
  • Kotlin 和惯用的书写方式,基于可变值“如果不为空,则...”

    假设我们有这样的代码 class QuickExample fun function argument SomeOtherClass if argument mutableProperty null doSomething argument
  • Proguard - 找不到任何超级类

    我收到此错误 Unexpected error while performing partial evaluation Class org apache log4j chainsaw Main Method
  • 使用 Glide 库设置图像加载完成后进度条的可见性

    您好 我想要一个图像进度条 该进度条将在图像加载时显示 但当图像加载完成时 我想将其设置为消失 早些时候我为此使用了毕加索库 但我不知道如何将它与 Glide 库一起使用 我知道有一些资源就绪功能 但我不知道如何使用它 谁能帮我 毕加索图书
  • 确定视图是否在屏幕上 - Android

    我对这个有点困惑 首先也是最重要的是 以下链接很有用 但是我提出了一些可见性问题 链接 检查视图可见性 https stackoverflow com questions 4628800 android how to check if a
  • 如何在 Android 中保存 Edittext 中的文本而不丢失文本的粗体、斜体等功能

    我想做的就是从 Edittext 中获取文本 该文本具有粗体和斜体等功能 并将其保存在文本文件中 但是当我读回并显示它时 这些功能丢失了 它们不显示 如何通过将文本保存在文本文件或任何文件中来保持丰富的功能 您可以使用Html toHtml
  • 从多个 TextView 中选择文本

    如何在android中从多个文本视图中选择文本 我已经尝试过以下代码 该代码一次仅适用于一个文本视图 我想一次性从许多文本视图中复制文本 android textIsSelectable true 你不能同时这样做 您需要在单个文本视图中设
  • 在DialogFragment中,onCreate应该做什么?

    我目前正在摆弄 DialogFragment 以学习使用它 我假设相比onCreateView onCreate 可以这样做 public void onCreate Bundle savedInstanceState super onCr
  • 进程被杀死后不会调用 onActivityResult

    我有一个主要活动 Main 和另一个活动 Sub 由 Main 调用 startActivityForResult new Intent this SubActivity class 25 当我在 Sub 时 我终止该进程 使用任务管理器或

随机推荐

  • LSTM Character-Aware Language Model

    DeepDGA中提到的自编码器 在字符级语言建模中非常有用 DeepDGA中 作者用该自编码器与生成对抗网络的效果作了对比 项目地址 https github com yoonkim lstm char cnn 代码来自 AAAI 2016
  • CentOS7.5.1804 Minimal 安装JDK1.8.0_172

    一 安装前检查 安装之前先检查一下系统有没有自带open jdk 命令 rpm qa grep java rpm qa grep jdk rpm qa grep gcj 如果没有输出信息表示没有安装 如果有输出信息 表示安装了 检查是否是自
  • C语言中动态内存的申请和释放

    什么是动态内存的申请和释放 当程序运行到需要一个动态分配的变量时 必须向系统申请取得堆中的一块所需大小的存储空间 用于存储该变量 当不再使用该变量时 也就是它的生命结束时 要显式释放它所占用的存储空间 这样系统就能对该堆空间进行再次分配 做
  • 用R语言如何进行贝叶斯网状meta的meta回归分析

    R语言通过许多不同的软件包来实现贝叶斯网状meta回归分析 其中一个常用的软件包是 rstanarm 你可以使用该软件包中的函数 stan glmer 来拟合模型 并使用 summary 函数来获取结果的统计信息 此外 你还可以使用 plo
  • 时间序列预测算法总结

    时间序列算法 time series data mining 主要包括decompose 分析数据的各个成分 例如趋势 周期性 prediction 预测未来的值 classification 对有序数据序列的feature提取与分类 cl
  • 【Python】Bezier曲线的绘制

    Bezier曲线的绘制 r u i J
  • AndroidStudio最常用快捷键总结

    默认在default的kaymap环境下的快捷键 最重要的快捷键 1 ctrl shift A 万能命令行 2 shift两次 查看资源文件 新建工程第一步操作 1 module设置把空包分层去掉 compact empty middle
  • java.lang.ClassNotFoundException解决办法

    java lang ClassNotFoundException com dsep util SessionListener at org apache catalina loader WebappClassLoader loadClass
  • 【MATLAB第10期】基于贝叶斯Bayes算法优化LSTM长短期记忆网络的多输入单输出回归预测模型思路框架

    基于贝叶斯Bayes算法优化LSTM长短期记忆网络的多输入单输出回归预测模型思路框架 前言 前面在 MATLAB第8期 讲解了基于贝叶斯Bayes算法优化LSTM长短期记忆网络的时间序列预测模型 即单输入数据时间序列预测 见本人知乎主页 思
  • 部署gitlab,模拟开发流程

    一 安装gitlab 1 需要先安装依赖包 yum install y curl policycoreutils python openssh server postfix 2 gitlab 下载网址 https mirrors tuna
  • 双系统下Ubuntu突然不能连接WiFi解决办法

    注意是突然不能连接 1 在Windows系统下 我的电脑 gt 管理 gt 设备管理 gt 网络适配器里面有个WiFi 2 选中右键属性 然后把那个运行电脑关机时关闭WiFi节省电脑的 去掉即可
  • 安装WSL,Ubuntu,子系统备份与迁移

    1 安装WSL及Ubuntu 在搜索框里打入cmd以管理员方式运行 键入wsl install并按回车 此命令将启用运行 WSL 并安装 Linux 的 Ubuntu 发行版 默认安装 wsl install 如果不想安装Ubuntu发行版
  • 基于Dlib进行人脸特征点检测的Python代码实现

    一 Python代码实现 import sys import os import glob import dlib import numpy as np import cv2 把imread中的路径修改为自己的图片路径 图片格式为jpeg格
  • Linux操作系统之tcp并发编程

    一 tcp并发编程 运行结果 多线程运行代码 运行结果 二 发送缓冲区与接收缓冲区 运行结果 为什么会出现以上的现象呢 因为在服务端与客户端都存在发送缓冲区与接收缓冲区
  • Unity插件 --- LeanTouch的使用

    在unity自带的asset store搜索 Lean touch 然后找到对应的资源 然后全部都导入到项目中 1 开启和关闭 private void OnEnable LeanTouch OnFingerDown HandeFinger
  • 浅读设计模式

    浅读设计模式 1 引言 2 重新认识一下UML 3 设计模式的七大原则 4 设计模式的分类 5 设计模式的具体说明 6 容易混淆的设计模式之间的区别 6 1创建型设计模式 6 2结构型设计模式 6 3行为型设计模式 6 4跨类对比 7 声明
  • 伪元素::after和::before的”前世今生“

    序言 在做前端页面时 需要做一些样式上的改变 使用伪元素很轻易就做到了 之前一直说伪元素还可以清除浮动 然后就想了解一下这东西到底能干什么 如下图 之前碰到的 为元素添加边框样式 小程序中修改radio checkbox的默认样式 都用到了
  • Blender_5_挤出

    这一专栏是我的学习笔记 小白 欢迎评论交流 在此感谢B站辣椒酱的教学视频 挺好玩的 1 挤出选区 选中面之后 快捷按钮栏选择 挤出 拖拽黄色的小圆 也可以在选中面之后 按快捷键E 很方便 下面是正方体 选中顶面之后挤出的效果 2 挤出流形
  • 数字IC设计——跨时钟域篇1(时钟域)

    数字IC设计 跨时钟域篇1 一 时钟域概要 1 CDC介绍 CDC clock domain crossing 检查 跨时钟域的检查 是对电路设计中同步电路设计的检查 非同步时钟没有固定的相位关系 这样Setup Hold不满足而产生了亚稳
  • Rk3399 Android9.0 恢复出厂设置流程

    Reset 流程 1 原生设置中响应 恢复出厂设置 功能 继而发出重置广播 Intent ACTION FACTORY RESET 2 frameWork层 接收到此广播 根据广播所携带的参数执行Android层的Reset设定 3 And