跪拜 Guibai
← Back to the summary

The Android Terminology Tangle: SDK, NDK, Framework, and Native Are Not on the Same Axis

NDK, SDK, APP, Framework, Native — How to Tell Them Apart?

When learning Android, it's easy to get tangled up in a few terms: SDK, NDK, APP, Framework, Native.

Sometimes you see things like:

Develop an App with the Android SDK.
Write C/C++ with the Android NDK.
An App calls Framework APIs.
The Framework eventually enters a native service.
Java has native methods.
A native crash occurred; check the tombstone.

Each sentence looks correct on its own, but put together they easily cause confusion:

Is the SDK the Framework?
Is the NDK the Native layer?
Does an App using C++ count as a native App?
Is the .so inside an App the same thing as a native service in the system?
Is it enough to understand that the Framework is the Java layer and Native is the C++ layer?
Is the "native" mentioned in system development the same concept as the native keyword in Java?

This article first clarifies the core issue: these terms are not concepts on the same dimension. 01_concept_coordinate_map.png

Some terms describe development toolkits, like SDK and NDK.

Some terms describe delivery form and runtime identity, like APP.

Some terms describe Android system layers, like Framework, Native, HAL, Kernel.

Some terms describe code language or runtime implementation, like Java/Kotlin, C/C++, JNI, native methods.

Mixing these dimensions leads to typical misunderstandings: thinking that using the NDK means doing Android Native layer development; thinking the SDK equals the Framework; thinking an App becomes a system native module just because it contains a .so; thinking a native crash is definitely an NDK problem.

Let's put the conclusions first:

SDK:
    The toolkit and API contract Android provides to developers, mainly for compiling, debugging, packaging, and running Android applications.

NDK:
    The native development toolkit Android provides for developers to write C/C++ code, typically compiling C/C++ into .so files and placing them inside the App.

APP:
    The application unit delivered to a device for installation and execution, manifested as an APK/AAB. At runtime, it is one or more processes, which can contain Java/Kotlin and also native .so files.

Framework:
    The framework layer of the Android system that provides capabilities upwards, including public APIs, system APIs, Framework Java code, system services in system_server, etc.

Native:
    A context-dependent term. It can refer to C/C++ code, the daemons/libraries/services of the system's native layer, or the JNI implementation behind Java native methods.

The real questions to ask first are:

Am I discussing a development tool, or a runtime layer?
Am I discussing a code language, or a system module?
Am I discussing what I see at compile time, or what actually executes on the device at runtime?

As long as these three questions are clear, NDK, SDK, APP, Framework, and Native will no longer be a jumbled mess.

1. First, Establish a Coordinate System: These Terms Are Not on the Same Line

Often, the difficulty isn't the definitions themselves, but that we place terms from different perspectives on a single line.

Let's first break them down from four perspectives:

Toolkit Dimension:
    SDK, NDK

Deliverable Dimension:
    APP, APK, AAB, library, .so

System Layering Dimension:
    App, Framework, System Service, Native Service, HAL, Kernel

Language and Runtime Implementation Dimension:
    Java/Kotlin, C/C++, ART, JNI, native method, native crash

The same object can fall into multiple dimensions simultaneously.

For example, a regular Android App:

From the deliverable perspective:
    It is an APK/AAB.

From the system layering perspective:
    It runs in the App layer.

From the development tool perspective:
    It is typically compiled, packaged, and debugged using the Android SDK.

From the language implementation perspective:
    It can be mainly written in Kotlin/Java, and can also contain .so files compiled from C/C++.

Another example, a video processing App using the NDK:

It is still an App.
It still runs within an App process and App sandbox.
It still uses the Android SDK to access APIs like Activity, Camera, MediaCodec.
It additionally uses the NDK to compile C/C++ into a native library.
Its .so is App native code, not automatically equivalent to an Android system native service.

So, don't rush to solve everything with a single phrase like "this is native." It's best to add a qualifier first:

Is this a native library inside an App?
Or a native daemon in AOSP?
Or the native implementation of a Framework JNI call?
Or the native keyword in a Java method declaration?
Or a "native App" in terms of product form?

Whether a term is clear depends on whether the context is clear.

2. What is the SDK? Why Isn't It the Framework?

02_sdk_vs_framework.png

SDK stands for Software Development Kit.

In the context of Android, the Android SDK can be understood as: a set of development entry points that Android provides to application developers.

It typically includes these things:

platforms/android-xx/android.jar:
    The Android API declarations used at compile time.

build-tools:
    Build and packaging tools like aapt2, d8, zipalign, apksigner.

platform-tools:
    Tools for interacting with devices, like adb, fastboot.

cmdline-tools:
    Command-line tools like sdkmanager, avdmanager, lint.

emulator and system images:
    For creating and running emulators.

Documentation, samples, API reference:
    For understanding API behavior and development methods.

The easiest point of confusion here is android.jar.

Many people see code written in an App like:

val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

Or:

startActivity(intent);

And think, "I am calling the SDK." This statement can be valid from a developer's perspective, but more accurately:

At compile time:
    Your code depends on the API declarations in the SDK.

At runtime:
    Your code calls the real Framework implementation within the device's system.

android.jar is more like a compilation contract. It tells the compiler:

These classes exist.
These methods can be called.
These are the parameters and return values.
These APIs belong to the scope visible to the current compileSdk.

But it is not the complete Framework that actually executes on the device.

At device runtime, the capabilities are truly provided by a whole set of system components in the system image: the Framework, ART, system_server, native services, HAL, Kernel, etc.

So, the relationship between the SDK and the Framework can be pinned down like this:

The SDK is the toolkit and API contract a developer sees when compiling and invoking Android capabilities.
The Framework is the implementation and abstraction layer within the Android system that provides these capabilities on the device.

To put it more directly:

The SDK is "how you compile, how you reference, and which APIs you can see."
The Framework is "who on the device actually implements these APIs, who actually handles these requests."

Therefore, the SDK is not the Framework. The SDK merely exposes a portion of the Framework's capabilities to App developers in the form of stable APIs.

3. What is the NDK? Why Isn't It the Android Native Layer?

03_ndk_vs_native_layer_v2.png

NDK stands for Native Development Kit.

Android's official core positioning for the NDK is clear: it is a set of tools that allows you to implement a portion of your App's code in C/C++.

The NDK typically includes these things:

Clang/LLVM toolchain:
    Used to compile C/C++ into machine code runnable on Android.

sysroot, headers, libraries:
    Provide native API declarations and linking entry points supported by Android.

CMake / ndk-build integration:
    Helps Gradle build native libraries.

ABI support:
    arm64-v8a, armeabi-v7a, x86_64, etc.

Debugging and symbol tools:
    Related capabilities like lldb, addr2line, objdump, readelf.

After using the NDK, the common result is the generation of one or more .so files:

app/src/main/jniLibs/arm64-v8a/libxxx.so
app/build/intermediates/merged_native_libs/...
APK/lib/arm64-v8a/libxxx.so

At App runtime, these .so files are loaded via JNI or other native entry points, and then C/C++ code executes within the App process.

Here's the key point: The NDK is not the Android system's Native layer itself.

The NDK is a toolkit. The Native layer is a runtime implementation or a system layer.

The relationship between these two concepts is more like this:

NDK:
    A native development toolkit for App developers.

App native library:
    An .so compiled with the NDK and installed along with the App.

Android native layer:
    The C/C++ system components, native libraries, native services, daemons, HAL-related implementations, etc., within AOSP.

For example, if you use the NDK to write an image filter library:

Kotlin/Java UI
  -> JNI
  -> libfilter.so
  -> C++ algorithm

This is called an App using the NDK to write a portion of native code.

But it does not mean you are modifying Android system native components like SurfaceFlinger, AudioFlinger, netd, vold, init, libbinder, libcutils.

So, when you see "NDK development," you must first ask:

Is this C/C++ code inside an App?
Or is it a C/C++ module within the AOSP system source code?

The former is typically application native development. The latter is closer to the native layer development discussed in full-system development.

4. What is an APP? Why Can an APP Contain Both SDK and NDK Elements?

An APP is not a language concept, nor is it a toolkit concept.

In Android, an APP is closer to a unit of delivery and execution.

It typically manifests as:

Development phase:
    An application project consisting of one or more Gradle modules.

Build artifact:
    An APK or AAB.

After installation:
    A packageName, corresponding to a UID, permissions, data directories, component declarations, etc.

At runtime:
    One or more Linux processes, typically running within an application sandbox.

An App can contain many things:

classes.dex:
    Bytecode compiled from Kotlin/Java.

resources.arsc and res/:
    Resource files.

AndroidManifest.xml:
    Declarations for components, permissions, features, providers, services, etc.

lib/arm64-v8a/*.so:
    Native libraries.

assets/:
    Raw resources.

So, the relationship between an App and the SDK/NDK is not a parallel one, but rather:

The App is the final deliverable and runtime entity.
The SDK is the primary Android toolkit and API contract used when developing this App.
The NDK is an additional native toolkit used when this App requires C/C++.

In common scenarios:

An App using only Kotlin/Java:
    Uses the SDK, may not use the NDK.

An App containing C/C++:
    Uses the SDK and also uses the NDK.

A system pre-installed App:
    Is still an App, but may use regular Android APIs, System APIs, or even access some hidden interfaces.

A platform Framework module:
    Is not a regular App; it is typically built and updated with the system image.

An App carrying a .so does not change its fundamental nature as an App.

It simply indicates:

A portion of this App's logic runs in native code.

It is still subject to the App's UID, SELinux domain, permission model, process sandbox, and API restrictions.

This is also a very important point during troubleshooting. For example, if a third-party App experiences a native crash:

Phenomenon:
    The tombstone shows SIGSEGV, libxxx.so.

Conclusion:
    This is a native crash.

But you cannot directly conclude:
    This is a problem with the Android system's native layer.

A more accurate judgment:
    First, check which process crashed, which library crashed, and whether the library comes from /data/app or /system/lib64, /vendor/lib64.

If the crash is in /data/app/.../lib/arm64/libxxx.so, it is most likely the App's own native library.

If the crash is in /system/bin/surfaceflinger, /system/bin/netd, /system/lib64/libbinder.so, /vendor/bin/hw/..., then it's more likely to enter the realm of system native, HAL, or vendor-side analysis.

5. What is the Framework? Why Is It Bigger Than the SDK?

The Framework is the framework layer of the Android system that provides capabilities to Apps and upper-layer modules.

It is not a single jar, nor a single process, and certainly not another name for the SDK.

From an App developer's perspective, the Framework looks like a set of APIs:

Activity
Service
ContentProvider
BroadcastReceiver
View
Window
PackageManager
ActivityManager
PowerManager
ConnectivityManager
TelephonyManager
CameraManager

From a system developer's perspective, the Framework is a set of system capability abstractions spanning multiple processes and modules:

frameworks/base/core:
    Framework Java classes that are also loaded within the App process.

frameworks/base/services:
    The implementation of a large number of system services within system_server.

Binder interfaces:
    The boundary for communication between the App process, system_server, and native services.

System API / hidden API:
    Non-public capabilities for internal use by system Apps, manufacturers, and the platform.

JNI bridge:
    The bridge where Framework Java code enters native implementation.

So, the core of the Framework is not the label "Java layer," but rather:

It abstracts complex underlying capabilities into system capabilities callable by upper layers.

For example, when you call this in an App:

val pm = context.packageManager
val info = pm.getPackageInfo(packageName, 0)

On the surface, it looks like just calling a Java/Kotlin API, but the real chain might be:

App process
  -> Framework API / proxy
  -> Binder
  -> system_server
  -> PackageManagerService
  -> System data like settings/packages.xml, permission status, installation status
  -> Binder return
  -> App receives the result

Here, the SDK only solves the compile-time problem of "can I call getPackageInfo."

The Framework is the system implementation that actually handles Package information, permissions, installation status, cross-process communication, and result return at device runtime.

You can remember this relationship first:

The SDK is the API window and tool collection that the Framework exposes to App developers.
The Framework is the implementation, services, and abstraction layer within the system that truly carries these APIs.

6. What is Native? Why Is It the Easiest to Confuse?

Native is the most confusing term here because it has different meanings in different contexts.

There are at least five common meanings:

First: Native code at the language level
    Refers to code like C/C++ that is compiled into native machine code for execution.

Second: The native method in Java syntax
    Refers to a Java method that has no Java implementation; its implementation is mapped to C/C++ via JNI.

Third: Native library within an App
    Refers to the .so files carried within an App's package, like libfoo.so.

Fourth: The Android system native layer
    Refers to native daemons, native services, and C/C++ libraries within AOSP, like init, logd, netd, SurfaceFlinger, libbinder.

Fifth: Native App in product form
    Refers to an App developed closer to the platform's native capabilities, as opposed to Web Apps, Hybrid Apps, or cross-platform shells.

All five can be abbreviated as "native," but they are not the same thing.

For example:

private native long nativeInit();

Here, native is a Java method modifier, meaning:

The implementation of this Java method is not in Java code, but in native code.

It is typically bound to a C/C++ function via JNI.

Another example:

/system/bin/surfaceflinger
/system/bin/netd
/system/lib64/libbinder.so
/vendor/bin/hw/android.hardware.camera.provider-service

Here, "native" is closer to the Android system native layer or vendor native implementation.

Another example:

APK/lib/arm64-v8a/libopencv_java4.so
APK/lib/arm64-v8a/libgame.so

Here, it refers to the native library carried by the App.

So, when you see the word "native," you must add a context qualifier:

native method?
native library?
native crash?
native service?
native layer?
native app?

Without context, the information carried by "native" is insufficient.

7. Viewing It in a Real Call Chain

04_runtime_call_chain.png

After discussing abstract concepts, it's best to place them in a call chain.

Assume an App opens the camera and also has a segment of C++ image processing logic:

App UI:
    Kotlin/Java writes the Activity, View, permission requests, and preview interface.

SDK:
    At compile time, uses Android API declarations like Camera2, Activity, Permission.

Framework:
    At runtime, the App calls Framework APIs like CameraManager.

Binder:
    The Framework proxy sends the request across processes to the system service.

System / Native Service:
    System components like the camera service handle the request.

HAL:
    Standard interfaces connect to the vendor's camera provider implementation.

Kernel / Driver:
    Drivers and hardware complete the actual data acquisition.

NDK:
    The App uses the NDK to compile a C++ image algorithm, producing libimage_filter.so.

App native library:
    The App calls libimage_filter.so via JNI to process image frames.

Organized into a chain:

Development phase:
    The Android SDK provides App APIs, build tools, adb, etc.
    The Android NDK provides C/C++ compilation and linking capabilities.

Installation phase:
    The App is packaged into an APK/AAB, which may contain dex, resources, manifest, .so files.

Runtime phase:
    The App process loads Framework classes and its own native libraries.
    The App requests system capabilities through Framework APIs.
    The Framework enters system_server or native services via Binder.
    System services further access HAL, vendor, kernel, and drivers.

In this chain, the position of each term is different:

SDK:
    Primarily from the development and compilation perspective.

NDK:
    Primarily from the C/C++ build and App native library perspective.

APP:
    Primarily from the installation package, process, permission, sandbox, and business function perspective.

Framework:
    Primarily from the system capability abstraction and runtime implementation perspective.

Native:
    Depends on context; could be an App .so, a system service, or a JNI method implementation.

This way, you won't misinterpret "I used the NDK" as "I am modifying the Android system native layer."

And you won't misinterpret "I called an SDK API" as "The SDK did everything for me on the device."

8. How to Quickly Determine Which Category a Problem Belongs To?

05_debug_decision_tree.png

When troubleshooting, you can use the following set of questions to quickly locate conceptual boundaries.

1. Is this a development tool issue?

If you encounter:

compileSdk configuration
minSdk / targetSdk
Gradle build failure
adb connection failure
Android SDK Platform not installed
Build Tools version issues
Signing, packaging, aapt2, d8, R8, lint

First, look at the SDK, Android Studio, Gradle, and build toolchain.

If the problem occurs during the compilation, packaging, installation, or debugging toolchain phase, first look at the SDK and build chain.

2. Is this a C/C++ build or ABI issue?

If you encounter:

CMakeLists.txt
ndkVersion
abiFilters
arm64-v8a / armeabi-v7a
undefined symbol
dlopen failed
JNI method not found
libxxx.so not packaged into APK
native debug symbols

First, look at the NDK, native library, ABI, and JNI chain.

If the problem occurs during the compilation, linking, loading, or JNI binding phase of the App's own C/C++ code, first look at the NDK and App native library.

3. Is this an App runtime identity issue?

If you encounter:

Insufficient permissions
Background restrictions
Foreground service restrictions
Application data directory
UID / packageName
AndroidManifest declarations
Component startup failure
targetSdk behavior changes

First, analyze based on the App's runtime identity.

If the problem is related to package, UID, permissions, components, manifest, or targetSdk behavior, first analyze based on the App's runtime identity.

4. Is this a Framework state or system service issue?

If you encounter:

ActivityManagerService
PackageManagerService
WindowManagerService
PowerManagerService
ConnectivityService
system_server
Binder call exception
Abnormal system API behavior
frameworks/base modifications

First, look at the Framework, system_server, and Binder call chain.

If the problem occurs within system capability abstractions, system service state machines, or cross-process call chains, first look at the Framework and system_server.

5. Is this a system native or HAL issue?

If you encounter:

surfaceflinger crash
netd anomaly
vold crash
logd, init, servicemanager
/system/lib64/*.so
/vendor/lib64/*.so
HAL service
vendor process
tombstone pointing to a system native process

Then, enter the Android native layer, HAL, vendor, or kernel boundary to investigate.

If the crashing process or core library comes from /system or /vendor, and belongs to a system service, native daemon, or HAL service, then proceed to system native analysis.

9. The Most Common Confusions

Confusion 1: SDK equals Framework

No. The SDK is a development toolkit and API contract; the Framework is the implementation and abstraction layer of system capabilities on the device.

The App depends on the APIs exposed by the SDK at compile time.
The App calls the Framework implementation within the device at runtime.

Confusion 2: NDK equals the Native layer

No. The NDK is a toolkit for App developers to write C/C++; the Android Native layer refers to the C/C++ daemons, services, libraries, HAL, etc., within the system layering.

Using the NDK allows you to write App native libraries.
Modifying the Android native layer typically involves working within AOSP, vendor, HAL, or system native services.

Confusion 3: An App using C++ is no longer an App

No.

Whether an App is an App primarily depends on whether it is installed, run, authorized, and managed in the form of an Android application.

Using Kotlin, Java, C++, Rust, or other languages inside it does not change its fundamental identity as an App.

A more appropriate phrasing is:

This is an App that contains native libraries.

Confusion 4: A native crash is an NDK crash

Not necessarily.

A native crash only indicates that the crash occurred in a native code path. It could come from:

The App's own .so
A third-party SDK's .so
A system native library
A native daemon
A HAL service
A vendor library

The entry point for judgment is not "is there a SIGSEGV," but:

Which process crashed?
What was the crashing thread doing?
Where does the .so in the backtrace come from?
Is the library path /data/app, or /system, /vendor?
Do the symbols belong to the App, a third-party library, Framework JNI, a native service, or HAL?

Confusion 5: Framework is Java, Native is C++

Too coarse.

The Framework indeed contains a lot of Java code, but the Framework also enters native via JNI, and its implementation includes native bridges and collaboration with underlying services.

Native indeed contains a lot of C/C++, but not all C/C++ belongs to the system native layer. An App's own .so is also C/C++, but it runs within the App process.

A more robust statement is:

The Framework is a system capability abstraction layer, not just a language label.
Native is an implementation method or system layer label, and must be judged together with the process, path, and module.

10. Pinning Down the Boundaries with a Table

Term Primary Dimension What It Is Common Location Most Easily Mistaken For
SDK Toolkit / API Contract Tools and public APIs needed for App development, compilation, debugging, and packaging Android SDK directory, Android Studio, Gradle configuration The Framework itself
NDK Toolkit / C/C++ Build Toolchain for implementing part of an App's logic in C/C++ ndk/, CMake, .so, JNI Android System Native Layer
APP Deliverable / Runtime Identity APK/AAB, package, UID, process, permissions, components /data/app, App process, manifest A fixed language implementation
Framework System Layer / Capability Abstraction Android APIs, system services, Framework Java, system_server, etc. frameworks/base, system_server, Manager/Service SDK
Native Language / Implementation / System Layer C/C++ code, native library, native service, JNI implementation, etc. .so, /system/bin, /vendor/bin, JNI NDK or simply C++

The most important thing about this table is not memorizing every cell, but remembering the relationship between the first and second columns:

SDK and NDK are about "how to develop."
APP is about "what is delivered and run."
Framework and Native are about "which layer the system is at during runtime and who implements it."

11. How to Speak Clearly in Practical Work to Avoid Misunderstandings?

If you want to express "I am writing an Android application," you can say:

I am doing App development, mainly using the Android SDK and Kotlin/Java.

If you want to express "I am writing C++ inside an App," you can say:

This App uses the NDK to compile a portion of native library, called via JNI.

If you want to express "I am modifying a system service," you can say:

I am modifying a Framework-layer system service, like PackageManagerService / ActivityManagerService.

If you want to express "I am modifying a system C++ service," you can say:

I am modifying an Android native service, like SurfaceFlinger / netd / vold.

If you want to express "I am looking at the hardware abstraction layer," you can say:

I am looking at a HAL service or vendor implementation, which sits between the Framework/native service and the kernel driver.

If you want to express "a native crash occurred," it's best to complete the sentence:

This is a native crash in an App process, crashed in libxxx.so under /data/app.

Or:

This is a system native process crash; the process is surfaceflinger, and the backtrace is mainly between /system/lib64 and vendor libraries.

Communicating this way is much clearer than a single phrase like "there's a native problem."

12. Further Reading

Summary: What is the Final Answer?

The core question of this article is:

How exactly to distinguish between NDK, SDK, APP, Framework, and Native?

It can be condensed into three layers of meaning.

First, SDK and NDK are toolkits, not system layers.

The SDK is for the general development, compilation, debugging, and packaging of Android Apps.
The NDK is for the compilation, linking, and debugging of C/C++ native libraries within an App.

Second, APP is a unit of delivery and execution, not representing a fixed language.

An App can use only Kotlin/Java, or it can contain C/C++ .so files.
An App using the NDK is still an App, just with an added portion of native code.

Third, Framework and Native are the layering and implementation contexts of the system at runtime.

The Framework is responsible for abstracting system capabilities into upper-layer APIs and system services.
Native needs context; it could be an App .so, a JNI implementation, a system native service, a native library, HAL, or vendor code.

So, the real method of distinction is not rote memorization of terms, but asking these questions first every time:

Is this a toolkit, or a runtime layer?
Is this a deliverable, or implementation code?
Is this the App's own native, or Android system native?
Is this the SDK API seen at compile time, or the Framework implementation at device runtime?

As long as these questions are asked correctly, the boundaries between NDK, SDK, APP, Framework, and Native will become very clear.

Comments

Top 1 from juejin.cn, machine-translated. The original thread is authoritative.

丨小夕

Explained very clearly [thumbs up]. I think a program only needs two core concepts. 1: compile-time / run-time. The SDK is just what's publicly exposed for you to call; as long as the runtime exists, even without the SDK you can craft your own API to fool the compiler, or use reflection to call it successfully. 2: in-process or out-of-process. Inside the process, the entire memory is visible to you, theoretically nothing can stop you. Framework code in Android, however, is loaded into your process.