AndroidにおけるPidとUidの違いと関係
この質問で何を調べたいのですか?
Android システムにおける Pid と Uid の概念と理解を調べる
試験の答え方
ご存知のとおり、Pid はプロセス ID、Uid はユーザー ID です。ただし、Android はコンピューターとは異なります。コンピューターの各ユーザーには Uid があります。どのユーザーがプログラムを起動するか、プログラムの Uid はそのユーザーです。 Android のすべてのプログラムには Uid があります。Uid があります。デフォルトでは、Android は、互いに異なる共通レベルの Uid を各プログラムに割り当てます。相互に呼び出しに使用する場合、Uid は次のとおりです。これにより、共有データには一定のセキュリティがかかり、ソフトウェア間で自由にデータを取得することができなくなります。同じアプリケーションには Uid が 1 つしかないため、アプリケーション内のアクティビティ間でアクセス許可の問題は発生しません。
PID
Android の PID の正式名は、Linux に由来する Process Identifier です。プロセスが開始されると、システムはプロセスに一意の識別子を割り当てます。プロセスが破棄された後、PID はシステムによってリサイクルされますが、 Android では通常、再割り当てされません。次のプロセスの PID は、前のプロセスの PID よりも大きくなります。ただし、同じ Android アプリに複数の PID を持つことができ、クラス宣言時にプロセス名を指定するだけで追加できるので非常に便利です。コードは次のとおりです。
<activity android:name=".TestActivty" android:process="com.xiaohan.test"/>
追加すると非常に便利ですが、同一アプリケーション(PID)内ではプログラム間の通信はほとんどがスレッド間通信になるように設計されており、PIDが独立するとプロセス間通信が発生するため、気軽には使えません。もちろん、上記のプライベート公開および許可公開方法を通じてデータ通信を実現することもできますが、システムのオーバーヘッドが比較的大きくなります。
UID
Android の UID は一般にユーザー識別子であると考えられており、これも Linux に由来しています。しかし、Android では異なります。Android はもともと単一ユーザー向けに設計されているため、UID はユーザーを区別するためのものではなく、異なるプログラム間でデータを共有するためのものです。Android の各プログラムには Uid があります。デフォルトでは、Android は互いに異なる共通レベルの Uid を各プログラムに割り当てます。したがって、プログラムが相互に呼び出すことを想定している場合、同じである必要があるのは Uid だけです。共有データについて 一定のセキュリティがあり、各ソフトウェア間で勝手にデータを取得することはできません。同じアプリケーションには Uid が 1 つしかないため、アプリケーション内のアクティビティ間でアクセス許可の問題は発生しません。
Android の UID はアプリケーションを識別するために使用され、UID はアプリケーションのインストール時に割り当てられ、アプリケーションが携帯電話に存在する間は変更されません。アプリケーションは uid を 1 つだけ持つことができ、アプリケーションの署名が同じである必要がある場合、複数のアプリケーションがsharedUserIdを使用して同じuidを共有できます。
UID の割り当て方法
アプリケーションの起動時、または携帯電話の起動時、PackageManagerService は apk を解析し、アプリに UID を割り当てます。具体的なプロセスは次のとおりです (Android 11 に基づく):
PackageManagerService.javaでは、PMSコンストラクタの初期化時に関数scanDirTracedLI()が実行され、scanDirTracedLI()ではscanDirLI()が実行され、次にscanPackageTracedLI()が実行され、次にscanPackageLI()が実行され、次に、addForInitLI( が実行されます。)、そして scanPackageNewLI() を実行します。もちろん、このプロセスには多くのコードの詳細が含まれます。この章の PKMS の部分を学習することをお勧めします。この scanPackageNewLI 関数では、mSettings.getSharedUserLPw() が実行されて共有ユーザーが取得されます。共有ユーザーが存在しない場合は、新しい共有ユーザーを作成します。次のコードを参照してください。
SharedUserSetting getSharedUserLPw(String name, int pkgFlags, int pkgPrivateFlags,
boolean create) throws PackageManagerException {
SharedUserSetting s = mSharedUsers.get(name);
if (s == null && create) {
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.userId = acquireAndRegisterNewAppIdLPw(s); //核心代码
if (s.userId < 0) {
// < 0 means we couldn't assign a userid; throw exception
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Creating shared user " + name + " failed");
}
Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
mSharedUsers.put(name, s);
}
return s;
}
上記のコードは、このアプリの SharedUserSetting 情報が作成されておらず、作成する必要がある場合に、情報を作成してから、acquireAndRegisterNewAppIdLPw 関数を呼び出して UID を割り当てることを示しています。
private int acquireAndRegisterNewAppIdLPw(SettingBase obj) {
// Let's be stupidly inefficient for now...
final int size = mAppIds.size();
//code1 从0开始,找到第一个未使用的ID,此处对应之前有应用被移除的情况,复用之前的ID
for (int i = mFirstAvailableUid; i < size; i++) {
if (mAppIds.get(i) == null) {
mAppIds.set(i, obj);
return Process.FIRST_APPLICATION_UID + i;
}
}
//code2 最多只能安装 9999 个应用
// None left?
if (size > (Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID)) {
return -1;
}
mAppIds.add(obj);
// code3 可以解释为什么普通应用的UID 都是从 10000开始的
return Process.FIRST_APPLICATION_UID + size;
}
上記のことから、APP に割り当てられた UID は次の原則に従っていることがわかります: 1) コード 1 から、ID は再利用できることがわかります。アプリがアンインストールされると、その ID はその後インストールされるアプリによって再利用されます。2 ) コード 2 から、ユーザー ID は 19999 を超えることができないことがわかります。これは、インストールできるアプリの数が 9999 を超えることができないことを意味します。それ以外の場合、インストールされたアプリには uid が割り当てられません。3) 各 UID は、プロセスより大きい数値です。 .FIRST_APPLICATION_UID、つまり、それらはすべて 10,000 より大きくなります。
AndroidのUIDの値
Android では、UID は実行可能プログラムに対応し、プログラムが Android システムに残っている間、UID は変更されません。サンドボックスの概念は、Android でプログラムを管理するために使用されます。さまざまなプログラムには一意の UID と PID があります。UID は、ファイル ディレクトリ、データベース アクセス、ネットワーク、センサー、ログなどを含む「リソース」を識別するために使用されます。Linux と同様です。 、それらは互いに影響しません。
通常、異なるアプリケーションは異なるプロセスで動作し、アプリケーション間の「リソース」にアクセスすることはできませんが、主にActivity、Service、ContentProviderをプロセス共有することで、異なるプログラム間のデータアクセスが実現できます。許可公開レベル: 完全公開、許可プロンプト公開、およびプライベート公開。
完全に露出した
これは、android:exported="true" による実装を参照します。AndroidMaindfest.xml で Activity、Service、または ContentProvider を宣言するときに、この属性を true に設定すると、クラスが外部データ アクセスを許可することを示します。宣言時にintentFilter属性を追加するとデフォルトでexportedがtrueとなり、強制的にfasleに設定することも可能です。他の設定 (exported/intentFilter) が行われていない場合、デフォルトのエクスポートは fasle、つまり外部に公開されません。次のコードに示すように:
<activity android:name=".TestActivty" android:exported="true"/>
許可プロンプトが公開される
AndroidMaindfest.xml で Activity、Service、または ContentProvider を宣言すると、アクセス許可が追加されます。これは、他のアプリケーションがこのクラスにアクセスする必要がある場合、以下に示すように、アプリケーション内でクラスが宣言されるときにアクセス許可を追加し、プライベート アクセス許可を宣言する必要があることを示します。
<activity android:name=".TestActivty" android:permission="com.xiaohan.permission"/>
//添加访问的权限说明
<uses-permission android:name="com.xiaohan.permission"/>
個人的な暴露
上記の 2 種類の公開方法とは異なり、異なるアプリケーションが相互にデータにアクセスできるようにする場合は、sharedUserId と同じ署名セットを使用して実装する必要があります。この方法でのみ、同じプロセスで実行できます (同じサンドボックス)、データへの相互アクセスを確保します。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xiaohan.test" //应用包名
android:sharedUserId="com.xiaohan.sharedUID" //暴露的唯一标识
android:sharedUserLabel="@string/app_name" //必须是引入资源文件中的字符串
android:versionCode="1"
android:versionName="1.1.0"
//安装位置,默认在内部目录,还包括auto:自动、 preferExternal:外置SD卡中
android:installLocation="internalOnly">
要約する
異なるアプリケーションには一意の UID があり、同じ UID が異なる PID を持つ可能性があります。
異なる PID 間のデータ公開にはプライベート公開と許可公開を使用でき、異なる UID には完全公開を使用できます。
アプリケーションがシステム アプリケーションの場合、アプリケーションのデータを他のアプリケーションに公開することなく直接アクセスできます。
やっと
Android の面接の質問をまとめました。上記の面接の質問に加え、[ Java の基本、コレクション、マルチスレッド、仮想マシン、リフレクション、ジェネリックス、同時プログラミング、Android の 4 つの主要コンポーネント、非同期タスク、メッセージ] も含まれていますメカニズム、UI描画、パフォーマンスチューニング、SDN、サードパーティフレームワーク、デザインパターン、Kotlin、コンピュータネットワーク、システム起動プロセス、Dart、Flutter、アルゴリズムとデータ構造、NDK、H.264、H.265、オーディオコーデック、FFmpeg 、OpenMax、OpenCV、OpenGL ES ]