Global Exception Handler: bản chất, nguyên lý hoạt động và triển khai trong dự án

Tác giả: IT Sectr Đã đăng: 2026-05-27 Thời gian đọc: 8 phút

Global Exception Handler — cơ chế tập trung để bắt các ngoại lệ chưa được xử lý, ngăn chặn ứng dụng di động bị treo. Theo Apple Developer, 2024, xử lý ngoại lệ đúng cách giảm số lượng sự cố treo xuống 40–60% và cải thiện trải nghiệm người dùng. Nếu không có trình xử lý như vậy, bất kỳ ngoại lệ chưa được xử lý nào trong luồng nền đều dẫn đến việc đóng ứng dụng ngay lập tức.

Điểm Chính

  • Global Exception Handler — điểm thu thập tập trung tất cả các ngoại lệ chưa được xử lý trong ứng dụng, ngăn chặn sự cố treo
  • iOS NSSetUncaughtExceptionHandler — hàm C để chặn các ngoại lệ Objective-C trên nền tảng Apple
  • Android Thread.setDefaultUncaughtExceptionHandler — cơ chế tích hợp sẵn của nền tảng để chặn ngoại lệ toàn cục
  • Ghi nhật ký trước khi đóng — nhiệm vụ chính của trình xử lý: lưu thông tin về sự cố trước khi kết thúc tiến trình
  • Suy giảm dần — trình xử lý cho phép hiển thị màn hình lỗi phù hợp thay vì đóng đột ngột

Global Exception Handler là gì?

Global Exception Handler — là cơ chế tập trung để bắt các ngoại lệ không được xử lý ở cấp độ hàm hoặc mô-đun riêng lẻ của ứng dụng. Trong bối cảnh phát triển di động, trình xử lý như vậy đóng vai trò là tuyến phòng thủ cuối cùng trước khi tiến trình kết thúc bất thường.

iOS và Android cung cấp API tích hợp để thiết lập trình xử lý toàn cục. Apple sử dụng NSSetUncaughtExceptionHandler cho môi trường Objective-C, trong khi Google cung cấp Thread.setDefaultUncaughtExceptionHandler trong Java/Kotlin. Cả hai cơ chế đều bắt các ngoại lệ không được cấu trúc try-catch bắt trên tất cả các luồng của ứng dụng.

Theo Crashlytics (Google, 2024), khoảng 25% sự cố treo xảy ra do ngoại lệ chưa được xử lý trong luồng nền — lĩnh vực mà Global Exception Handler đặc biệt quan trọng. Các nhà phát triển thường tập trung vào luồng UI, quên mất các thao tác bất đồng bộ.

Sử dụng trình xử lý toàn cục không thay thế xử lý lỗi cục bộ mà bổ sung cho nó. Nhiệm vụ chính là lưu tối đa thông tin về trạng thái ứng dụng tại thời điểm ngoại lệ và kết thúc đúng cách.

Trình xử lý ngoại lệ toàn cục hoạt động như thế nào

Cơ chế hoạt động của Global Exception Handler dựa trên việc chặn các tín hiệu hệ điều hành hoặc ngoại lệ thời gian chạy. Khi mã ném ra một ngoại lệ không bị bắt bởi bất kỳ khối try-catch nào, quyền điều khiển được chuyển đến trình xử lý đã đăng ký trước.

Trên iOS, trình xử lý được đăng ký qua NSSetUncaughtExceptionHandler và nhận đối tượng NSException với dấu vết ngăn xếp đầy đủ. Trên Android, sử dụng Thread.setDefaultUncaughtExceptionHandler, chấp nhận ThreadThrowable — cung cấp quyền truy cập vào loại ngoại lệ, thông báo và ngăn xếp cuộc gọi.

Sau khi nhận dữ liệu sự cố, trình xử lý thực hiện ba hành động bắt buộc: ghi nhật ký vào bộ nhớ cục bộ, gửi báo cáo đến Crashlytics hoặc Sentry và kết thúc ứng dụng đúng cách. Theo Apple WWDC 2023, thời gian thực thi của trình xử lý bị giới hạn ở 5 giây — sau đó hệ thống buộc kết thúc tiến trình.

Đối với ứng dụng Swift từ iOS 13, Signals API đã được giới thiệu, xử lý không chỉ ngoại lệ mà còn cả tín hiệu hệ điều hành — SIGABRT, SIGSEGV và SIGBUS, mở rộng phạm vi bảo vệ của trình xử lý đến các lỗi bộ nhớ cấp thấp.

Triển khai Global Exception Handler trên iOS

Triển khai trình xử lý toàn cục trên iOS yêu cầu thiết lập hàm C qua NSSetUncaughtExceptionHandler. Trình xử lý được gọi đồng bộ tại thời điểm ngoại lệ chưa được xử lý và nhận ngữ cảnh lỗi đầy đủ.

objective-c
void handleUncaughtException(NSException exception) {
    NSDictionary userInfo = [exception userInfo];
    NSArray stackTrace = [exception callStackSymbols];
    NSString reason = [exception reason];

    // Lưu nhật ký sự cố vào tệp cục bộ
    NSString logPath = [NSSearchPathForDirectoriesInDomains(
        NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    [exceptionLog writeToFile:logPath atomically:YES];
}

int main(int argc, char argv[]) {
    NSSetUncaughtExceptionHandler(&handleUncaughtException);
    return UIApplicationMain(argc, argv, nil, nil);
}

Đặc điểm quan trọng của triển khai iOS: trình xử lý chỉ bắt ngoại lệ Objective-C. Lỗi Swift sử dụng cơ chế throw-catch không đến được trình xử lý này — chúng yêu cầu xử lý riêng qua Swift Error Handling. Bắt đầu từ iOS 14, Apple khuyến nghị kết hợp NSSetUncaughtExceptionHandler với Signals API để có phạm vi bảo vệ tối đa.

Theo Apple Technical Note TN2151, sau khi gọi trình xử lý, ứng dụng phải kết thúc trong vòng 5 giây. Bất kỳ nỗ lực nào tiếp tục thực thi sau khi trở về từ trình xử lý đều dẫn đến hành vi không xác định và sự cố treo tiếp theo.

Triển khai Global Exception Handler trên Android

Android cung cấp cơ chế linh hoạt hơn để xử lý ngoại lệ toàn cục qua Thread.setDefaultUncaughtExceptionHandler. Trình xử lý nhận tham chiếu đến luồng nơi xảy ra ngoại lệ và chính đối tượng Throwable.

kotlin
class GlobalExceptionHandler : Thread.UncaughtExceptionHandler {

    override fun uncaughtException(thread: Thread, throwable: Throwable) {
        // Lưu nhật ký sự cố vào tệp
        val stackTrace = throwable.stackTraceToString()
        val crashLog = "CRASH: ${thread.name}\n${stackTrace}"

        val file = File(context.cacheDir, "crash_log.txt")
        file.writeText(crashLog)

        // Gửi đến Crashlytics
        FirebaseCrashlytics.getInstance()
            .recordException(throwable)

        // Kết thúc tiến trình
        android.os.Process.killProcess(
            android.os.Process.myPid()
        )
    }
}

// Thiết lập trong Application.onCreate
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Thread.setDefaultUncaughtExceptionHandler(
            GlobalExceptionHandler()
        )
    }
}

Sự khác biệt chính của triển khai Android: mỗi luồng có trình xử lý riêng và setDefaultUncaughtExceptionHandler thiết lập trình xử lý cho tất cả các luồng không có trình xử lý cá nhân được chỉ định. Điều này đảm bảo phạm vi bảo vệ toàn cục — từ luồng UI đến AsyncTask nền và coroutine.

Trên Android 12+, có giới hạn: sau khi gọi uncaughtException, ứng dụng phải kết thúc trong vòng 100 mili giây. Nếu trình xử lý thực hiện các thao tác kéo dài, hệ thống có thể chấm dứt tiến trình trước khi nhật ký được ghi. Nên sử dụng dịch vụ nền để gửi báo cáo sự cố.

Phương pháp hay nhất với Global Exception Handler

Quy tắc đầu tiên — không cố gắng khôi phục hoạt động của ứng dụng sau ngoại lệ chưa được xử lý. Trạng thái ứng dụng sau sự cố là không xác định và tiếp tục thực thi có thể dẫn đến hỏng dữ liệu người dùng.

Giảm thiểu thời gian thực thi của trình xử lý

Giới hạn thời gian — ràng buộc kỹ thuật chính của Global Exception Handler. Trên iOS là 5 giây, trên Android — 100 mili giây. Bên trong trình xử lý, chỉ nên lưu một tập dữ liệu tối thiểu: loại ngoại lệ, ngăn xếp cuộc gọi và trạng thái của một vài biến chính.

Việc gửi yêu cầu mạng, ghi vào cơ sở dữ liệu và tuần tự hóa phức tạp nên được hoãn lại sang cơ chế trì hoãn — ví dụ: lưu nhật ký vào tệp và gửi ở lần khởi động ứng dụng tiếp theo.

Kết hợp với hệ thống báo cáo sự cố

Dịch vụ báo cáo sự cố — Firebase Crashlytics, Sentry, Bugsnag — thiết lập trình xử lý toàn cục của riêng chúng. Nếu nhà phát triển thiết lập trình xử lý tùy chỉnh bổ sung, họ cần chuyển quyền điều khiển cho hệ thống báo cáo sự cố sau các hành động của mình. Trên Android, sử dụng hợp thành trình xử lý: thực thi logic của bạn, sau đó gọi trình xử lý trước đó.

Đối với Firebase Crashlytics, khuyến nghị không thiết lập Thread.setDefaultUncaughtExceptionHandler tùy chỉnh — SDK Crashlytics tự động thực hiện việc này khi khởi tạo.

Ghi nhật ký thông tin bổ sung

Ngữ cảnh người dùng — ngoài ngăn xếp cuộc gọi tiêu chuẩn, nên ghi nhật ký phiên bản ứng dụng, phiên bản hệ điều hành, kích thước bộ nhớ khả dụng và thời gian hoạt động trước sự cố. Dữ liệu này cực kỳ quan trọng để tái tạo và khắc phục sự cố.

Trên iOS, có thể sử dụng NSSetUncaughtExceptionHandler không chỉ để ghi mà còn để lưu trữ tạm thời trong NSUserDefaults với cờ synchronize — điều này đảm bảo tính bền vững ngay cả khi tiến trình kết thúc ngay lập tức.

Kiểm tra trình xử lý trước khi phát hành

Kiểm tra bắt buộc — Global Exception Handler phải được kiểm tra ở mọi giai đoạn của CI/CD. Trên iOS, có thể kích hoạt ngoại lệ thử nghiệm qua @throw NSException, trên Android — qua throw RuntimeException(). Xác minh rằng trình xử lý được gọi, nhật ký được lưu và ứng dụng kết thúc đúng cách.

Theo Google I/O 2023, hơn 30% sự cố treo trong sản xuất xảy ra trên các thiết bị mà nhà phát triển chưa kiểm tra — các phiên bản Android khác nhau, phần sụn tùy chỉnh, bộ nhớ hạn chế.

Lỗi thường gặp khi sử dụng trình xử lý

Lỗi đầu tiên và phổ biến nhất — cố gắng tiếp tục thực thi ứng dụng sau khi xử lý ngoại lệ. Sau khi gọi uncaughtException, ứng dụng ở trạng thái không ổn định và bất kỳ thao tác nào tiếp theo có thể gây ra lỗi xếp tầng và hỏng dữ liệu.

Lỗi thứ hai — thực hiện các thao tác kéo dài bên trong trình xử lý. Yêu cầu mạng, ghi tệp lớn hoặc tính toán phức tạp không hoàn thành trước khi tiến trình bị buộc kết thúc. Theo Apple Technical Q&A QA1468, cố gắng gửi yêu cầu HTTP bên trong trình xử lý là nguyên nhân hàng đầu dẫn đến mất báo cáo sự cố.

Lỗi thứ ba — bỏ qua các luồng nền. Global Exception Handler chỉ thiết lập cho luồng chính không bảo vệ khỏi sự cố trong coroutine, DispatchQueue, AsyncTask hoặc RxJava. Trên Android, mỗi luồng phải có trình xử lý riêng — và setDefaultUncaughtExceptionHandler chỉ giải quyết điều này cho các luồng không có trình xử lý cá nhân.

Lỗi thứ tư — thiếu phương án dự phòng cho tín hiệu hệ điều hành. NSSetUncaughtExceptionHandler trên iOS không bắt SIGABRT, SIGSEGV và SIGBUS. Các tín hiệu này yêu cầu thiết lập trình xử lý riêng qua API sigaction. Nhà phát triển chỉ phát hiện ra điều này khi ứng dụng bị treo mà không có một báo cáo sự cố nào.

Lỗi thứ năm — ghi nhật ký dữ liệu bảo mật. Nhật ký sự cố có thể chứa email, mã thông báo xác thực hoặc dữ liệu cá nhân của người dùng. Điều này vi phạm GDPRNguyên tắc đánh giá App Store của Apple. Luôn lọc dữ liệu truyền qua regex hoặc danh sách trắng các trường được phép.

Câu hỏi thường gặp

Có thể khôi phục ứng dụng sau ngoại lệ toàn cục không?

Không — sau khi gọi Global Exception Handler, trạng thái ứng dụng không xác định. Bất kỳ nỗ lực nào tiếp tục thực thi đều có thể dẫn đến hỏng dữ liệu. Hành động đúng duy nhất là lưu nhật ký sự cố và kết thúc tiến trình.

Global Exception Handler có bắt tất cả các loại lỗi không?

Không phải tất cả — trên iOS, NSSetUncaughtExceptionHandler chỉ bắt ngoại lệ Objective-C. Lỗi Swift và tín hiệu hệ điều hành (SIGSEGV, SIGABRT) yêu cầu trình xử lý riêng. Trên Android, Thread.setDefaultUncaughtExceptionHandler bắt tất cả RuntimeException nhưng không bắt lỗi mã gốc qua JNI.

Làm thế nào để chuyển quyền điều khiển cho hệ thống báo cáo sự cố sau trình xử lý của tôi?

Lưu tham chiếu đến trình xử lý trước đó qua Thread.getDefaultUncaughtExceptionHandler() trước khi thiết lập trình xử lý của bạn. Ở cuối trình xử lý của bạn, gọi previousHandler.uncaughtException(thread, throwable) — điều này đảm bảo Crashlytics hoặc Sentry nhận được dữ liệu của chúng.

Làm gì nếu sự cố xảy ra trong mã gốc C/C++?

Đối với mã gốc, cần xử lý tín hiệu qua sigaction() — SIGSEGV, SIGABRT, SIGBUS. Trên Android, bạn có thể sử dụng Google Breakpad hoặc Crashpad. Trên iOS từ phiên bản 13, Signals API có sẵn để xử lý ngoại lệ mach.

Global Exception Handler có thể ảnh hưởng đến hiệu suất không?

Không — việc thiết lập trình xử lý chỉ ảnh hưởng đến thời điểm xảy ra ngoại lệ. Trong hoạt động bình thường của ứng dụng, không có chi phí. Rủi ro duy nhất là rò rỉ bộ nhớ nếu trình xử lý giữ tham chiếu đến Activity hoặc Context, ngăn chặn việc thu gom rác.

Tổng kết

  • Global Exception Handler — tuyến phòng thủ cuối cùng trước sự cố, bắt buộc trong mọi ứng dụng sản xuất
  • iOS NSSetUncaughtExceptionHandler bắt ngoại lệ Objective-C với giới hạn xử lý 5 giây
  • Android Thread.setDefaultUncaughtExceptionHandler hoạt động cho tất cả luồng không có trình xử lý cá nhân
  • Thời gian thực thi của trình xử lý tối thiểu — lưu dữ liệu và kết thúc tiến trình mà không cố gắng khôi phục
  • Tín hiệu hệ điều hành (SIGSEGV, SIGABRT) không bị bắt bởi trình xử lý tiêu chuẩn — cần API sigaction
  • Hệ thống báo cáo sự cố nên được gọi qua hợp thành trình xử lý, chuyển quyền điều khiển sau logic của bạn
  • Kiểm tra trình xử lý trong CI/CD — bước bắt buộc ngăn mất báo cáo sự cố trong sản xuất

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm