android.process.media crash后现象研究之一

android.process.media crash后现象研究之二 做实验如下: C:\>adb shell ps |grep android.process.media app_14 817 197 107556 24456 ffffffff afd0c74c S android.process.media F:\send_file>adb shell kill 817 F:\send_file>adb logcat 发现: 杀掉 阅读详情

android.process.media crash后现象研究


在ActivityManagerService启动android.process.media进程时,在启动进程后会调用attachApplicationLocked,在其中利用Binder的linkToDeath方法来接收进程退出消息。

在进程crash后,如果进程中存在Service在运行或者有Provider等待运行则进程会被自动运行。



ActivityManagerService.java

    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {...
         // If this application record is still attached to a previous
        // process, clean it up now.
        if (app.thread != null) {
            handleAppDiedLocked(app, true);
        }

        String processName = app.processName;
        try {
            thread.asBinder().linkToDeath(new AppDeathRecipient(
                    app, pid, thread), 0);
        } catch (RemoteException e) {
            app.resetPackageList();
            startProcessLocked(app, "link fail", processName);
            return false;
        }


一旦监控的进程退出,则AppDeathRecipient.binderDied()将被调用。

    private final class AppDeathRecipient implements IBinder.DeathRecipient {
        final ProcessRecord mApp;
        final int mPid;
        final IApplicationThread mAppThread;

        AppDeathRecipient(ProcessRecord app, int pid,
                IApplicationThread thread) {
            mApp = app;          //待监听应用进程
            mPid = pid;           //被监听进程ID
            mAppThread = thread;  //被监听进程的binder句柄
        }

        public void binderDied() {
            synchronized(ActivityManagerService.this) {
                dyingPidLocked = mPid;
                appDiedLocked(mApp, mPid, mAppThread);     //调用appDiedLocked
                dyingPidLocked = -1;
            }
        }
    }

    final void appDiedLocked(ProcessRecord app, int pid,
            IApplicationThread thread) {...
        mProcDeaths[0]++;          //死亡的进程个数加1,代表自最近启动进程以来死亡的进程数,startProcessLocked中会清零
        
        BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
        synchronized (stats) {
            stats.noteProcessDiedLocked(app.info.uid, pid);        //从电池用量计数进程表中删除
        }

        // Clean up already done if the process has been re-started.
        if (app.pid == pid && app.thread != null &&
                app.thread.asBinder() == thread.asBinder()) {
            if (!app.killedBackground) {
                Slog.i(TAG, "Process " + app.processName + " (pid " + pid
                        + ") has died.");
            }
            EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
            if (localLOGV) Slog.v(
                TAG, "Dying app: " + app + ", pid: " + pid
                + ", thread: " + thread.asBinder());
            boolean doLowMem = app.instrumentationClass == null;
            handleAppDiedLocked(app, false);

            if (doLowMem) {
                // If there are no longer any background processes running,
                // and the app that died was not running instrumentation,
                // then tell everyone we are now low on memory.
                boolean haveBg = false;
                for (int i=mLruProcesses.size()-1; i>=0; i--) {
                    ProcessRecord rec = mLruProcesses.get(i);
                    if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
                        haveBg = true;
                        break;
                    }
                }
                
                if (!haveBg) {
                    Slog.i(TAG, "Low Memory: No more background processes.");
                    EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
                    long now = SystemClock.uptimeMillis();
                    for (int i=mLruProcesses.size()-1; i>=0; i--) {
                        ProcessRecord rec = mLruProcesses.get(i);
                        if (rec != app && rec.thread != null &&
                                (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
                            // The low memory report is overriding any current
                            // state for a GC request.  Make sure to do
                            // heavy/important/visible/foreground processes first.
                            if (rec.setAdj <= HEAVY_WEIGHT_APP_ADJ) {
                                rec.lastRequestedGc = 0;
                            } else {
                                rec.lastRequestedGc = rec.lastLowMemory;
                            }
                            rec.reportLowMemory = true;
                            rec.lastLowMemory = now;
                            mProcessesToGc.remove(rec);
                            addProcessToGcListLocked(rec);
                        }
                    }
                    scheduleAppGcsLocked();
                }
            }
        } else if (app.pid != pid) {
            // A new process has already been started.
            Slog.i(TAG, "Process " + app.processName + " (pid " + pid
                    + ") has died and restarted (pid " + app.pid + ").");
            EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
        } else {
            if (DEBUG_PROCESSES) {
                Slog.d(TAG, "Received spurious death notification for thread "
                        + thread.asBinder());
            }
            if (app.bad) {
                // When the process is marked "bad" because of its frequent crashes,
                // WindowManagerService may lose focus window and go into infinite loop.
                // Find a top alive activity from mHistory to recover from the wrong loop.
                mMainStack.resumeTopActivityLocked(null);
            }
        }
    }

    private final void handleAppDiedLocked(ProcessRecord app,
            boolean restarting) {
        cleanUpApplicationRecordLocked(app, restarting, -1);
        if (!restarting) {
            mLruProcesses.remove(app);
        }

        // Just in case...
        if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) {
            if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " +mMainStack.mPausingActivity);
            mMainStack.mPausingActivity = null;
        }
        if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) {
            mMainStack.mLastPausedActivity = null;
        }

        // Remove this application's activities from active lists.
        mMainStack.removeHistoryRecordsForAppLocked(app);

        boolean atTop = true;
        boolean hasVisibleActivities = false;

        // Clean out the history list.
        int i = mMainStack.mHistory.size();
        if (localLOGV) Slog.v(
            TAG, "Removing app " + app + " from history with " + i + " entries");
        while (i > 0) {
            i--;
            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
            if (localLOGV) Slog.v(
                TAG, "Record #" + i + " " + r + ": app=" + r.app);
            if (r.app == app) {
                if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
                    if (localLOGV) Slog.v(
                        TAG, "Removing this entry!  frozen=" + r.haveState
                        + " finishing=" + r.finishing);
                    mMainStack.mHistory.remove(i);
                    sendHistoryChangeNoti(r.task.taskId);

                    r.inHistory = false;
                    mWindowManager.removeAppToken(r);
                    if (VALIDATE_TOKENS) {
                        mWindowManager.validateAppTokens(mMainStack.mHistory);
                    }
                    r.removeUriPermissionsLocked();

                } else {
                    // We have the current state for this activity, so
                    // it can be restarted later when needed.
                    if (localLOGV) Slog.v(
                        TAG, "Keeping entry, setting app to null");
                    if (r.visible) {
                        hasVisibleActivities = true;
                    }
                    r.app = null;
                    r.nowVisible = false;
                    if (!r.haveState) {
                        r.icicle = null;
                    }
                }

                r.stack.cleanUpActivityLocked(r, true);
                r.state = ActivityState.STOPPED;
            }
            atTop = false;
        }

        app.activities.clear();
        
        if (app.instrumentationClass != null) {
            Slog.w(TAG, "Crash of app " + app.processName
                  + " running instrumentation " + app.instrumentationClass);
            Bundle info = new Bundle();
            info.putString("shortMsg", "Process crashed.");
            finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
        }

        if (!restarting) {
            if (!mMainStack.resumeTopActivityLocked(null)) {
                // If there was nothing to resume, and we are not already
                // restarting this process, but there is a visible activity that
                // is hosted by the process...  then make sure all visible
                // activities are running, taking care of restarting this
                // process.
                if (hasVisibleActivities) {
                    mMainStack.ensureActivitiesVisibleLocked(null, 0);
                }
            }
        }
    }


在此决定是否重启该进程或进程中正在运行的Service,并清除所有Provider及Service记录

    /**
     * Main code for cleaning up a process when it has gone away.  This is
     * called both as a result of the process dying, or directly when stopping 
     * a process when running in single process mode.
     */
    private final void cleanUpApplicationRecordLocked(ProcessRecord app,
            boolean restarting, int index) {
        if (index >= 0) {
            mLruProcesses.remove(index);
        }

        mProcessesToGc.remove(app);

        synchronized(app) {
            if (!app.bad && (app.crashDialog != null)) {
                app.crashDialog.dismiss();
            }
            app.crashDialog = null;
        }

        if (app.anrDialog != null) {
            app.anrDialog.dismiss();
            app.anrDialog = null;
        }
        if (app.waitDialog != null) {
            app.waitDialog.dismiss();
            app.waitDialog = null;
        }

        app.crashing = false;
        app.notResponding = false;
        
        app.resetPackageList();
        app.thread = null;
        app.forcingToForeground = null;
        app.foregroundServices = false;

        killServicesLocked(app, true);

        boolean restart = false;

        int NL = mLaunchingProviders.size();
        
        // Remove published content providers.
        if (!app.pubProviders.isEmpty()) {
            Iterator<ContentProviderRecord> it = app.pubProviders.values().iterator();
            while (it.hasNext()) {
                ContentProviderRecord cpr = it.next();
                cpr.provider = null;
                cpr.app = null;

                // See if someone is waiting for this provider...  in which
                // case we don't remove it, but just let it restart.
                int i = 0;
                if (!app.bad) {
                    for (; i<NL; i++) {
                        if (mLaunchingProviders.get(i) == cpr) {
                            restart = true;
                            break;
                        }
                    }
                } else {
                    i = NL;
                }

                if (i >= NL) {
                    removeDyingProviderLocked(app, cpr);
                    NL = mLaunchingProviders.size();
                }
            }
            app.pubProviders.clear();
        }
        
        // Take care of any launching providers waiting for this process.
        if (checkAppInLaunchingProvidersLocked(app, false)) { //仅当有应用依赖与某Provider且此Provider尚未publish则会自动重启crash进程,所有Provider将会在进程运行时被启动
            restart = true;
        }
        
        // Unregister from connected content providers.
        if (!app.conProviders.isEmpty()) {
            Iterator it = app.conProviders.keySet().iterator();
            while (it.hasNext()) {
                ContentProviderRecord cpr = (ContentProviderRecord)it.next();
                cpr.clients.remove(app);
            }
            app.conProviders.clear();
        }
        
        skipCurrentReceiverLocked(app);

        // Unregister any receivers.
        if (app.receivers.size() > 0) {
            Iterator<ReceiverList> it = app.receivers.iterator();
            while (it.hasNext()) {
                removeReceiverLocked(it.next());
            }
            app.receivers.clear();
        }
        
        // If the app is undergoing backup, tell the backup manager about it
        if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
            if (DEBUG_BACKUP) Slog.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
            try {
                IBackupManager bm = IBackupManager.Stub.asInterface(
                        ServiceManager.getService(Context.BACKUP_SERVICE));
                bm.agentDisconnected(app.info.packageName);
            } catch (RemoteException e) {
                // can't happen; backup manager is local
            }
        }

        // If the caller is restarting this app, then leave it in its
        // current lists and let the caller take care of it.
        if (restarting) {
            return;
        }

        if (!app.persistent) {
            if (DEBUG_PROCESSES) Slog.v(TAG,
                    "Removing non-persistent process during cleanup: " + app);
            mProcessNames.remove(app.processName, app.info.uid);
            if (mHeavyWeightProcess == app) {
                mHeavyWeightProcess = null;
                mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
            }
        } else if (!app.removed) {
            // This app is persistent, so we need to keep its record around.
            // If it is not already on the pending app list, add it there
            // and start a new process for it.
            app.thread = null;
            app.forcingToForeground = null;
            app.foregroundServices = false;
            if (mPersistentStartingProcesses.indexOf(app) < 0) {
                mPersistentStartingProcesses.add(app);
                restart = true;
            }
        }
        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
                "Clean-up removing on hold: " + app);
        mProcessesOnHold.remove(app);

        if (app == mHomeProcess) {
            mHomeProcess = null;
            mHomeTask = -1;
        }
        
        if (restart) {
            // We have components that still need to be running in the
            // process, so re-launch it.
            mProcessNames.put(app.processName, app.info.uid, app);
            startProcessLocked(app, "restart", app.processName);    //重启crash的应用
        } else if (app.pid > 0 && app.pid != MY_PID) {
            // Goodbye!
            synchronized (mPidsSelfLocked) {
                if (dyingPidLocked == -1) {
                    mPidsSelfLocked.remove(app.pid);
                } else {
                    mPidsSelfLocked.remove(dyingPidLocked);
                }

                mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
            }

            // If the dyingPid matches app.pid, there is no race between deatch
            // and re-birth, so it's ok to clear app.pid here
            if ((dyingPidLocked == -1) || (dyingPidLocked == app.pid)) {
                app.setPid(0);
            } else {
                if (DEBUG_PROCESSES) Slog.v(TAG, "hhmm - Race, skipped setting app.pid to 0" );
            }
        }
    }

以下函数将清除进程app内的Service及所有连接,如果allowRestart为true且非多次crash(<2),则将发消息以重启该服务。
    private final void killServicesLocked(ProcessRecord app,boolean allowRestart) {
        // 当进程crash时,allowRestart必为true
  
        // Clean up any connections this application has to other services.
        if (app.connections.size() > 0) {
            Iterator<ConnectionRecord> it = app.connections.iterator();
            while (it.hasNext()) {
                ConnectionRecord r = it.next();
                removeConnectionLocked(r, app, null);
            }
        }
        app.connections.clear();

        if (app.services.size() != 0) { //存在Service否?
            // Any services running in the application need to be placed
            // back in the pending list.
            Iterator<ServiceRecord> it = app.services.iterator();
            while (it.hasNext()) {
                ServiceRecord sr = it.next();
                synchronized (sr.stats.getBatteryStats()) {
                    sr.stats.stopLaunchedLocked();
                }
                sr.app = null;
                sr.executeNesting = 0;
                if (mStoppingServices.remove(sr)) {
                    if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
                }
                
                boolean hasClients = sr.bindings.size() > 0;
                if (hasClients) {
                    Iterator<IntentBindRecord> bindings
                            = sr.bindings.values().iterator();
                    while (bindings.hasNext()) {
                        IntentBindRecord b = bindings.next();
                        if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b
                                + ": shouldUnbind=" + b.hasBound);
                        b.binder = null;
                        b.requested = b.received = b.hasBound = false;
                    }
                }

                if (sr.crashCount >= 2) { //如果多次crash
                    Slog.w(TAG, "Service crashed " + sr.crashCount
                            + " times, stopping: " + sr);
                    EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
                            sr.crashCount, sr.shortName, app.pid);
                    bringDownServiceLocked(sr, true); //移除Service
                } else if (!allowRestart) {
                    bringDownServiceLocked(sr, true);
                } else {
                    boolean canceled = scheduleServiceRestartLocked(sr, true); //在此发起请求重起Service
                    
                    // Should the service remain running?  Note that in the
                    // extreme case of so many attempts to deliver a command
                    // that it failed, that we also will stop it here.
                    if (sr.startRequested && (sr.stopIfKilled || canceled)) {
                        if (sr.pendingStarts.size() == 0) {
                            sr.startRequested = false;
                            if (!hasClients) {
                                // Whoops, no reason to restart!
                                bringDownServiceLocked(sr, true);
                            }
                        }
                    }
                }
            }

            if (!allowRestart) {
                app.services.clear();
            }
        }

        // Make sure we have no more records on the stopping list.
        int i = mStoppingServices.size();
        while (i > 0) {
            i--;
            ServiceRecord sr = mStoppingServices.get(i);
            if (sr.app == app) {
                mStoppingServices.remove(i);
                if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
            }
        }
        
        app.executingServices.clear();
    }


Android RescueParty机制解析:从系统崩溃到数据挽救的渐进式自救 在移动操作系统领域,系统稳定性是用户体验的核心基石。Android系统通过一套名为RescueParty的智能监控与修复机制,实现了对系统崩溃和启动循环等严重故障的自动化处理。其工作原理基于对系统服务器崩溃频率、原生崩溃事件和关键应用连续失败等多维度指标的实时监控,一旦检测到异常模式,便会触发预设的急救等级。这一机制的技术价值在于,它能够在系统面临软件层面崩溃时,通过渐进式的修复策略(如重启系统、清除应用缓存、重置运行时权限等),最大限度地保护用户数据,避免设备直接“变砖”。在实际应用场景中,RescueP 阅读详情

相关推荐

Gemma 3n端侧部署实战:Android原生多模态离线推理指南

多模态大模型正从云端走向终端,而端侧视觉语言模型(VLM)的核心挑战在于如何在资源受限的移动设备上实现低延迟、高可靠、真离线的推理。其技术原理依赖于轻量化架构设计(如MatFormer)、INT4量化压缩、运行时契约封装(.task格式)与Android原生AI运行时(ai-edge-litert)深度协同;技术价值体现在摆脱网络依赖、保障数据隐私、降低服务成本,并支持无网场景下的实时交互;典型应用场景包括离线教育识别、工业设备图解、老年助视问答等对可用性与安全性要求严苛的领域;本文聚焦Gemma 3n这一

weixin_33979203的博客 443

Android - android.process.media意外停止解决方法

  android.process.media has stopped unexpectedly, android.process.media意外停止的解决方法。  这几天手机经常出现: android.process.media意外停止,在网上查了一下有说用刷机解决的,借助于androidforums的一个帖子解决了该问题。  我的C8500解决方法:  设置 - 应用程序 - 管理应用程序 - 按目录键选择过滤 - 全部 - 媒体存储 - 清除数据 解决!  也有人通过                 

灯塔ADA的专栏 13万+

Android开发学习链路和教程规划

这是一套系统化的Android开发教程,采用全新链路式教学法,从Linux内核到应用上线全流程解析。教程特色在于每个知识点都涵盖底层原理、源码链路、使用方法和工程治理四大维度,确保开发者获得完整认知体系。课程分为三个阶段:底层运行环境(Linux内核、Binder、Zygote等)、项目构建与运行时(Gradle、APK安装、资源系统等)、四大组件与UI开发(Activity、View、Jetpack等)。

9年Android老兵,专注车载系统与移动架构。深耕Java/Kotlin,玩转Lua/Python。擅长百度/高德地图深度定制,分享拒绝浅尝辄止的硬核干货。 66

2.7 深入理解ContentProvider

第7章 深入理解ContentProvider 7.1 概述 本章重点分析ContentProvider、SQLite、Cursor query、close函数的实现及ContentResolver openAssetFileDescriptor函数。为了帮助读者进一步理解本章的知识点,笔者特意挑选了四条分析路线。 第一条:以客户端进程通过MediaStore.Images.Media类的静态函数query来查询MediaProvider中Image相关信息为入口点,分析系统如何创建和启动Media.

外星人的杂货铺 1121

【安卓学习之myt】adb常用命令(+视频图标+在线反编译)

adb shell pm list packages 所有软件包adb shell pm list packages -s 只输出系统的包adb shell pm list packages -3 只输出第三方的包adb install D:\123.apk 安装应用adb -r install D:\123.apk 重新安装apkadb shell ls -l /sdcard/Temp/log 查看文件列表。

任我飞的博客 1759

android MediaProvider和MediaScanner详解

关于Android媒体存储和手机数据库扫描流程以及优化的部分代码贴图

实例分析:android.process.media由于调用进程crash而退出

Log: 09-13 11:46:42.093 14778 17309 I dalvikvm: Ljava/lang/RuntimeException;: No memory in memObj 09-13 11:46:42.093 14778 17309 I dalv

cloudwu007的专栏 3868

深入理解Android卷1全

深入理解Android 卷1 不是扫描版的,是全版电子书的,非PDF,可编辑,各种阅览器以打开!包括书签和同步目录! 第1章 阅读前的准备工作 / 1 1.1 系统架构 / 2 1.1.1 Android系统架构 / 2 1.1.2 本书的架构 / 3 1.2 搭建开发环境 / 4 1.2.1 下载源码 / 4 1.2.2 编译源码 / 6 1.3 工具介绍 / 8 1.3.1 Source Insight介绍 / 8 1.3.3 Busybox的使用 / 11 1.4 本章小结 / 12 第2章 深入理解JNI / 13 2.1 JNI概述 / 14 2.2 学习JNI的实例:MediaScanner / 15 2.3 Java层的MediaScanner分析 / 16 2.3.1 加载JNI库 / 16 2.3.2 Java的native函数和总结 / 17 2.4 JNI层MediaScanner的分析 / 17 2.4.1 注册JNI函数 / 18 2.4.2 数据类型转换 / 22 2.4.3 JNIEnv介绍 / 24 2.4.4 通过JNIEnv操作jobject / 25 2.4.5 jstring介绍 / 27 2.4.6 JNI类型签名介绍 / 28 2.4.7 垃圾回收 / 29 2.4.8 JNI中的异常处理 / 32 2.5 本章小结 / 32 第3章 深入理解init / 33 3.1 概述 / 34 3.2 init分析 / 34 3.2.1 解析配置文件 / 38 3.2.2 解析service / 42 3.2.3 init控制service / 48 3.2.4 属性服务 / 52 3.3 本章小结 / 60 第4章 深入理解zygote / 61 4.1 概述 / 62 4.2 zygote分析 / 62 4.2.1 AppRuntime分析 / 63 4.2.2 Welcome to Java World / 68 4.2.3 关于zygote的总结 / 74 4.3 SystemServer分析 / 74 4.3.1 SystemServer的诞生 / 74 4.3.2 SystemServer的重要使命 / 77 4.3.3 关于 SystemServer的总结 / 83 4.4 zygote的分裂 / 84 4.4.1 ActivityManagerService发送请求 / 84 4.4.2 有求必应之响应请求 / 86 4.4.3 关于zygote分裂的总结 / 88 4.5 拓展思考 / 88 4.5.1 虚拟机heapsize的限制 / 88 4.5.2 开机速度优化 / 89 4.5.3 Watchdog分析 / 90 4.6 本章小结 / 93 第5章 深入理解常见类 / 95 5.1 概述 / 96 5.2 以“三板斧”揭秘RefBase、sp和wp / 96 5.2.1 第一板斧——初识影子对象 / 96 5.2.2 第二板斧——由弱生强 / 103 5.2.3 第三板斧——破解生死魔咒 / 106 5.2.4 轻量级的引用计数控制类LightRefBase / 108 5.2.5 题外话-三板斧的来历 / 109 5.3 Thread类及常用同步类分析 / 109 5.3.1 一个变量引发的思考 / 109 5.3.2 常用同步类 / 114 5.4 Looper和Handler类分析 / 121 5.4.1 Looper类分析 / 122 5.4.2 Handler分析 / 124 5.4.3 Looper和Handler的同步关系 / 127 5.4.4 HandlerThread介绍 / 129 5.5 本章小结 / 129 第6章 深入理解Binder / 130 6.1 概述 / 131 6.2 庖丁解MediaServer / 132 6.2.1 MediaServer的入口函数 / 132 6.2.2 独一无二的ProcessState / 133 6.2.3 时空穿越魔术-defaultServiceManager / 134 6.2.4 注册MediaPlayerService / 142 6.2.5 秋风扫落叶-StartThread Pool和join Thread Pool分析 / 149 6.2.6 你彻底明白了吗 / 152 6.3 服务总管ServiceManager / 152 6.3.1 ServiceManager的原理 / 152 6.3.2 服务的注册 / 155 6.3.3 ServiceManager存在的意义 / 158 6.4 MediaPlayerService和它的Client / 158 6.4.1 查询ServiceManager / 158 6.4.2 子承父业 / 159 6.5 拓展思考 / 162 6.5.1 Binder和线程的关系 / 162 6.5.2 有人情味的讣告 / 163 6.5.3 匿名Service / 165 6.6 学以致用 / 166 6.6.1 纯Native的Service / 166 6.6.2 扶得起的“阿斗”(aidl) / 169 6.7 本章小结 / 172 第7章 深入理解Audio系统 / 173 7.1 概述 / 174 7.2 AudioTrack的破解 / 174 7.2.1 用例介绍 / 174 7.2.2 AudioTrack(Java空间)分析 / 179 7.2.3 AudioTrack(Native空间)分析 / 188 7.2.4 关于AudioTrack的总结 / 200 7.3 AudioFlinger的破解 / 200 7.3.1 AudioFlinger的诞生 / 200 7.3.2 通过流程分析AudioFlinger / 204 7.3.3 audio_track_cblk_t分析 / 230 7.3.4 关于AudioFlinger的总结 / 234 7.4 AudioPolicyService的破解 / 234 7.4.1 AudioPolicyService的创建 / 235 7.4.2 重回AudioTrack / 245 7.4.3 声音路由切换实例分析 / 251 7.4.4 关于AudioPolicy的总结 / 262 7.5 拓展思考 / 262 7.5.1 DuplicatingThread破解 / 262 7.5.2 题外话 / 270 7.6 本章小结 / 272 第8章 深入理解Surface系统 / 273 8.1 概述 / 275 8.2 一个Activity的显示 / 275 8.2.1 Activity的创建 / 275 8.2.2 Activity的UI绘制 / 294 8.2.3 关于Activity的总结 / 296 8.3 初识Surface / 297 8.3.1 和Surface有关的流程总结 / 297 8.3.2 Surface之乾坤大挪移 / 298 8.3.3 乾坤大挪移的JNI层分析 / 303 8.3.4 Surface和画图 / 307 8.3.5 初识Surface小结 / 309 8.4 深入分析Surface / 310 8.4.1 与Surface相关的基础知识介绍 / 310 8.4.2 SurfaceComposerClient分析 / 315 8.4.3 SurfaceControl分析 / 320 8.4.4 writeToParcel和Surface对象的创建 / 331 8.4.5 lockCanvas和unlockCanvasAndPost分析 / 335 8.4.6 GraphicBuffer介绍 / 344 8.4.7 深入分析Surface的总结 / 353 8.5 SurfaceFlinger分析 / 353 8.5.1 SurfaceFlinger的诞生 / 354 8.5.2 SF工作线程分析 / 359 8.5.3 Transaction分析 / 368 8.5.4 关于SurfaceFlinger的总结 / 376 8.6 拓展思考 / 377 8.6.1 Surface系统的CB对象分析 / 377 8.6.2 ViewRoot的你问我答 / 384 8.6.3 LayerBuffer分析 / 385 8.7 本章小结 / 394 第9章 深入理解Vold和Rild / 395 9.1 概述 / 396 9.2 Vold的原理与机制分析 / 396 9.2.1 Netlink和Uevent介绍 / 397 9.2.2 初识Vold / 399 9.2.3 NetlinkManager模块分析 / 400 9.2.4 VolumeManager模块分析 / 408 9.2.5 CommandListener模块分析 / 414 9.2.6 Vold实例分析 / 417 9.2.7 关于Vold的总结 / 428 9.3 Rild的原理与机制分析 / 428 9.3.1 初识Rild / 430 9.3.2 RIL_startEventLoop分析 / 432 9.3.3 RIL_Init分析 / 437 9.3.4 RIL_register分析 / 444 9.3.5 关于Rild main函数的总结 / 447 9.3.6 Rild实例分析 / 447 9.3.7 关于Rild的总结 / 459 9.4 拓展思考 / 459 9.4.1 嵌入式系统的存储知识介绍 / 459 9.4.2 Rild和Phone的改进探讨 / 462 9.5 本章小结 / 463 第10章 深入理解MediaScanner / 464 10.1 概述 / 465 10.2 android.process.media分析 / 465 10.2.1 MSR模块分析 / 466 10.2.2 MSS模块分析 / 467 10.2.3 android.process.media媒体扫描工作的流程总结 / 471 10.3 MediaScanner分析 / 472 10.3.1 Java层分析 / 472 10.3.2 JNI层分析 / 476 10.3.3 PVMediaScanner分析 / 479 10.3.4 关于MediaScanner的总结 / 485 10.4 拓展思考 / 486 10.4.1 MediaScannerConnection介绍 / 486 10.4.2 我问你答 / 487 10.5 本章小结 / 488

安卓:android.process.media意外停止解决方法

android.process.media has stopped android.process.media意外停止的解决方法。 管理应用程序- 全部 - 媒体存储 - 清除数据 管理应用程序- 全部 - 下载管理 - 清除数据 参考:http://androidforums.com/g1-support/4000-android-process-media-crash-con...

weixin_30865427的博客 395

晶晨S905L3S/S905L3SB芯片刷机实战:BL加载工具与线刷固件全解析

本文针对晶晨S905L3S/S905L3SB芯片电视盒子刷机时常见的2%失败问题,提供了两种核心解决方案。一是使用已集成特殊通信协议的专用版USB Burning Tool(如V2.2.5/V2.2.7),二是采用旧版工具配合独立的BootLoader加载工具。文章详细解析了两种方案的原理、操作步骤、固件选择及常见问题排查,旨在帮助用户成功完成刷机,让老旧设备焕发新生。

weixin_29238147的博客 1107

Windows中的TLS 1.2启用方法(IIS、C#、.Net framework)

折腾几天了windows中的tls1.2启用方法!特此记录一下 开发背景: 在一个用.net framework 2.0开发的客户端程序里面嵌入功能调用第三方物联网相关接口,服务器上有一个restful接口用于接收第三方上报的数据及处理,最后再调用第三方的物联网相关接口。本机开发环境Windows 10,客户服务器是Windows Server 2008 R2。 第一次写这种物联网相关的接口调用,而且第三方提供的文档比较简单,最基本的报文示例都没。开发环境里面各种摸索一步一个坑,首先在发送HTTP请求前

dl1314ld的博客 1万+

Android 稳定性【篇一:日志调试技能汇总】

Android开发过程中调试和日志分析是必不可少的,当前汇总分析android系统不同类型的日志抓取的原理

qq_27672101的博客 1883

如何在离线的电脑上部署一个本地Deepseek(使用ollama)

例如,如果您的显卡显存为 16GB,官方推荐使用 32b 大小的 DeepSeek 模型。请根据您的硬件配置选择适合的模型版本,以获得最佳性能。首先我们需要将ollama和chatbox的安装包,Deepseek模型文件通过U盘或者光盘的形式导入到这台不能联网的电脑上。按照时间排序,找到最大的那个文件,就是gguf格式的模型,复制出来,改名为qwen2.5-coder0.5b.gguf。:基于开源模型(如 QWEN 和 LLAMA)微调,参数量从 1.5B 到 70B 不等,适合本地硬件部署。

qq_41854911的博客 1万+

android原生增加崩溃日志文件写入本地

Application的onCreate()中 通过XCrashHandlerUtils.getInstance().init(this);

加油吧,少年! 407

回归预测 | MATLAB实现MPR多元多项式回归

回归预测 | MATLAB实现MPR多元多项式回归

机器学习之心的博客,关注并私信文章链接,获取对应文章源码和数据。 1645

YOLOv12涨点改进 | 全网首发,Conv改进篇 | CVPR 2025 | YOLOv12引入FDConv频率动态卷积,含A2C2f_FDConv二次创新模块,能够捕捉更加丰富和复杂的特征信息

本文提出了一种改进YOLOv12目标检测模型的方法——频率动态卷积(FDConv)。FDConv通过增强卷积核的频率响应多样性,使模型能够更好地处理不同频率信息,从而提高检测精度。该方法包含三个关键组件:傅里叶离散权重(FDW)实现频率分组,核空间调制(KSM)动态调整频率响应,以及频率带调制(FBM)进行频域调节。实验结果表明,FDConv能以较少的参数增长(仅增加3.6M)显著提升模型性能,在目标检测、实例分割等任务中优于传统动态卷积方法。该方法可灵活集成到ResNet、ConvNeXt等多种架构中。

Ai缝合怪、助力小伙伴高效发论文 421

Android版本差异适配方案(5.0-11.0)

Android版本差异适配方案(5.0-9.0) 一个好的APP最好支持90%设备,由于不同版本系统提供的API可能不同,所以了解不同版本间系统差异很重要,这样才能更好的适配更多的智能设备。你的应用足不足够健壮要看你的应用在主流版本运行是否流畅。这篇文章记录开发过程中遇到的相对重要以及常用的适配方案,希望对读者有所帮助。 Android 版本号及对应的版本名 版本号 版本名 中文名 ...

博由心生,福泽一生 6715

TC397 EB MCAL开发从0开始系列 之 [17.1] ETH配置实战 - ping/发送

TC397 MCAL 从0开始之 ETH ping测试

yy九歌的博客 1505

Android12 U盘挂载流程学习(一)

这是开机流程的一个重要步骤,标志着user正式启动,而系统启动的第一个用户的id就是0,会走到这里。// /data/media/0/Android/data挂载到/mnt/user/0/emulated/0/Android/data。// /data/media/0/Android/obb挂载到/mnt/user/0/emulated/0/Android/obb。// 挂载/dev/fuse到/mnt/user/0/usb0,访问/mnt/user/0/usb0就会指向/dev/fuse。

c025200的博客 1659

人员行为规范检测:YOLOv8+C#实现工厂车间安全监控,违规即报警零延迟

该方案通过YOLOv8的装备检测与姿态估计的动作识别,结合C#的实时管控能力,实现了从“被动巡检”到“主动预警”的转变。相比传统人工,违规响应速度提升10倍,全年可减少90%以上的安全隐患。方案已在3家制造企业落地,支持自定义违规规则(如新增“吸烟”“未系安全带”),可根据车间场景灵活扩展。需要完整的模型训练配置文件(含数据集增强脚本)或C#系统源码(视频处理+报警模块)的,评论区扣“SafetyDetect”,可直接获取部署版本~

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1174

C#串口通信从入门到精通(7)——整数/浮点数与二进制、八进制、十六进制之间的转换与C#实现

本文详细介绍由博主开发的DataConvert串口通信帮助类的用法,该帮助类涵盖了串口通信领域所有的数据转换方法,帮助大家快速编写串口通信程序!

qq_34059233的博客 2879

Android AI Coding:平台语义驱动的开发工作流重构

Android开发正从语法补全迈向平台契约治理。AI coding并非通用代码生成,而是深度理解Activity生命周期、Context持有规则、R.java编译机制与Runtime行为漂移等Android特有语义的技术实践。其核心价值在于将开发者角色从实现者升级为‘平台宪法仲裁者’,通过Manifest约束、SDK版本感知和资源ID校验等机制,确保AI输出符合Android平台运行时契约。典型应用场景包括安全的Context注入、Gradle构建期AI校验、ANR崩溃现场时空重建及Clean Archit

weixin_34253126的博客 462

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Android Google XTS

GMS全称为Google Mobile Service,即谷歌移动服务。GMS是Google开发并推动Android的动力,是Google提供的Mobile Device上的一系列应用服务。

qq_27672101的博客 2183

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Unity Android log view(Android Debug Bridge)

Android Debug Bridge

蛰伏--当你不够强大时,就不要放弃努力 4158

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Android 7系统日志(七)实战调试与常见问题分析

Android 日志系统实战调试指南 本文基于前六篇原理分析,提供真实工程问题的解决方案速查与典型案例。 核心问题速查表:涵盖8类常见日志问题(如logcat无输出、日志丢失、时间错乱等),提供可能原因、排查命令与对应原理章节。 典型案例分析: 日志突然消失:通过logcat -g检查缓冲区状态,-S定位日志滥用者,调整缓冲区大小或优化高频日志代码。 chatty消息泛滥:因循环日志触发合并机制,建议采用采样率控制或使用VERBOSE级别。 开机日志丢失:因logd启动晚于内核日志,需通过dmesg或pst

AfinalStone的专栏 286

Android CameraService启动流程深度解析:从系统启动到服务就绪

在Android系统开发中,系统服务启动流程是理解Framework层运作机制的基础。系统服务通过Binder IPC机制为上层应用提供核心功能接口,其启动通常遵循从init进程解析、进程fork到服务注册的标准化路径。CameraService作为Android多媒体子系统中的关键服务,负责管理相机硬件资源、仲裁多应用访问并桥接HAL层实现。其启动流程涉及init脚本解析、独立进程模型、HAL服务发现与设备枚举等核心技术环节,对于解决相机黑屏、权限异常等工程问题具有重要价值。本文基于Android P源码

weixin_30466039的博客 294
上一篇: Android消息处理探秘
下一篇: android.process.media crash后现象研究之二
cloudwu007
博客等级 码龄18年 42粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值