Merge "Generate user consent dialog for device log access" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
648426f3fe
@@ -6668,10 +6668,9 @@
|
||||
android:exported="false">
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.android.server.logcat.LogAccessConfirmationActivity"
|
||||
android:theme="@style/Theme.Dialog.Confirmation"
|
||||
<activity android:name="com.android.server.logcat.LogAccessDialogActivity"
|
||||
android:theme="@style/Theme.DeviceDefault.Dialog.Alert.DayNight"
|
||||
android:excludeFromRecents="true"
|
||||
android:process=":ui"
|
||||
android:label="@string/log_access_confirmation_title"
|
||||
android:exported="false">
|
||||
</activity>
|
||||
|
||||
23
core/res/res/drawable/grant_permissions_buttons_bottom.xml
Normal file
23
core/res/res/drawable/grant_permissions_buttons_bottom.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2022 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@android:color/system_accent1_100"/>
|
||||
<corners android:topLeftRadius="4dp" android:topRightRadius="4dp"
|
||||
android:bottomLeftRadius="12dp" android:bottomRightRadius="12dp"/>
|
||||
</shape>
|
||||
23
core/res/res/drawable/grant_permissions_buttons_top.xml
Normal file
23
core/res/res/drawable/grant_permissions_buttons_top.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2022 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@android:color/system_accent1_100"/>
|
||||
<corners android:topLeftRadius="12dp" android:topRightRadius="12dp"
|
||||
android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp"/>
|
||||
</shape>
|
||||
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
** Copyright 2022, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="380dp"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:paddingLeft="24dp"
|
||||
android:paddingRight="24dp"
|
||||
android:paddingTop="24dp"
|
||||
android:paddingBottom="24dp"
|
||||
android:background="?attr/colorSurface">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/log_access_image_view"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:src="@drawable/ic_doc_document"
|
||||
tools:layout_editor_absoluteX="148dp"
|
||||
tools:layout_editor_absoluteY="35dp"
|
||||
android:gravity="center" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/log_access_dialog_title"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:text="@string/log_access_confirmation_title"
|
||||
android:textAppearance="?attr/textAppearanceLarge"
|
||||
android:textColor="@android:color/system_neutral1_900"
|
||||
android:gravity="center" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/log_access_dialog_body"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/log_access_confirmation_body"
|
||||
android:textAppearance="@style/PrimaryAllowLogAccess"
|
||||
android:gravity="center" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/log_access_dialog_allow_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/log_access_confirmation_allow"
|
||||
style="@style/PermissionGrantButtonTop"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:clipToOutline="true"
|
||||
android:gravity="center" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/log_access_dialog_deny_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/log_access_confirmation_deny"
|
||||
style="@style/PermissionGrantButtonBottom"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:clipToOutline="true"
|
||||
android:gravity="center" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -5731,16 +5731,17 @@
|
||||
<!-- Title for the harmful app warning dialog. [CHAR LIMIT=40] -->
|
||||
<string name="harmful_app_warning_title">Harmful app detected</string>
|
||||
|
||||
<!-- Title for the log access confirmation dialog. [CHAR LIMIT=40] -->
|
||||
<string name="log_access_confirmation_title">System log access request</string>
|
||||
<!-- Title for the log access confirmation dialog. [CHAR LIMIT=NONE] -->
|
||||
<string name="log_access_confirmation_title">Allow <xliff:g id="log_access_app_name" example="Example App">%s</xliff:g> to access all device logs?</string>
|
||||
<!-- Label for the allow button on the log access confirmation dialog. [CHAR LIMIT=20] -->
|
||||
<string name="log_access_confirmation_allow">Only this time</string>
|
||||
<!-- Label for the deny button on the log access confirmation dialog. [CHAR LIMIT=20] -->
|
||||
<string name="log_access_confirmation_deny">Don\u2019t allow</string>
|
||||
|
||||
<!-- Content for the log access confirmation dialog. [CHAR LIMIT=NONE]-->
|
||||
<string name="log_access_confirmation_body"><xliff:g id="log_access_app_name" example="Example App">%s</xliff:g> requests system logs for functional debugging.
|
||||
These logs might contain information that apps and services on your device have written.</string>
|
||||
<string name="log_access_confirmation_body">Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps you trust to access all device logs.
|
||||
\n\nIf you don’t allow this app to access all device logs, it can still access its own logs, and your device manufacturer may still be able to access some logs or info on your device. Learn more
|
||||
</string>
|
||||
|
||||
<!-- Privacy notice do not show [CHAR LIMIT=20] -->
|
||||
<string name="log_access_do_not_show_again">Don\u2019t show again</string>
|
||||
|
||||
@@ -1499,5 +1499,43 @@ please see styles_device_defaults.xml.
|
||||
<item name="textColor">#555555</item>
|
||||
</style>
|
||||
|
||||
<!-- The style for log access consent text -->
|
||||
<style name="AllowLogAccess">
|
||||
<item name="android:layout_width">332dp</item>
|
||||
<item name="android:textSize">24sp</item>
|
||||
<item name="android:textColor">@android:color/system_neutral1_900</item>
|
||||
<item name="android:fontFamily">google-sans</item>
|
||||
</style>
|
||||
|
||||
<style name="PrimaryAllowLogAccess">
|
||||
<item name="android:layout_width">332dp</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textColor">@android:color/system_neutral1_900</item>
|
||||
<item name="android:fontFamily">google-sans</item>
|
||||
</style>
|
||||
|
||||
<style name="PermissionGrantButtonTop"
|
||||
parent="@android:style/Widget.DeviceDefault.Button.Borderless.Colored">
|
||||
<item name="android:layout_width">332dp</item>
|
||||
<item name="android:layout_height">56dp</item>
|
||||
<item name="android:layout_marginTop">2dp</item>
|
||||
<item name="android:layout_marginBottom">2dp</item>
|
||||
<item name="android:fontFamily">google-sans-medium</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textColor">@android:color/system_neutral1_900</item>
|
||||
<item name="android:background">@drawable/grant_permissions_buttons_top</item>
|
||||
</style>
|
||||
|
||||
<style name="PermissionGrantButtonBottom"
|
||||
parent="@android:style/Widget.DeviceDefault.Button.Borderless.Colored">
|
||||
<item name="android:layout_width">332dp</item>
|
||||
<item name="android:layout_height">56dp</item>
|
||||
<item name="android:layout_marginTop">2dp</item>
|
||||
<item name="android:layout_marginBottom">2dp</item>
|
||||
<item name="android:fontFamily">google-sans-medium</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textColor">@android:color/system_neutral1_900</item>
|
||||
<item name="android:background">@drawable/grant_permissions_buttons_bottom</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -3883,6 +3883,10 @@
|
||||
<java-symbol type="string" name="log_access_confirmation_deny" />
|
||||
<java-symbol type="string" name="log_access_confirmation_title" />
|
||||
<java-symbol type="string" name="log_access_confirmation_body" />
|
||||
<java-symbol type="layout" name="log_access_user_consent_dialog_permission" />
|
||||
<java-symbol type="id" name="log_access_dialog_title" />
|
||||
<java-symbol type="id" name="log_access_dialog_allow_button" />
|
||||
<java-symbol type="id" name="log_access_dialog_deny_button" />
|
||||
|
||||
<java-symbol type="string" name="config_defaultAssistantAccessComponent" />
|
||||
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.logcat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.logcat.ILogcatManagerService;
|
||||
import android.util.Slog;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.app.AlertActivity;
|
||||
import com.android.internal.app.AlertController;
|
||||
|
||||
|
||||
/**
|
||||
* This dialog is shown to the user before an activity in a harmful app is launched.
|
||||
*
|
||||
* See {@code PackageManager.setLogcatAppInfo} for more info.
|
||||
*/
|
||||
public class LogAccessConfirmationActivity extends AlertActivity implements
|
||||
DialogInterface.OnClickListener {
|
||||
private static final String TAG = LogAccessConfirmationActivity.class.getSimpleName();
|
||||
|
||||
private String mPackageName;
|
||||
private IntentSender mTarget;
|
||||
private final ILogcatManagerService mLogcatManagerService =
|
||||
ILogcatManagerService.Stub.asInterface(ServiceManager.getService("logcat"));
|
||||
|
||||
private int mUid;
|
||||
private int mGid;
|
||||
private int mPid;
|
||||
private int mFd;
|
||||
|
||||
private static final String EXTRA_UID = "uid";
|
||||
private static final String EXTRA_GID = "gid";
|
||||
private static final String EXTRA_PID = "pid";
|
||||
private static final String EXTRA_FD = "fd";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
|
||||
mUid = intent.getIntExtra("uid", 0);
|
||||
mGid = intent.getIntExtra("gid", 0);
|
||||
mPid = intent.getIntExtra("pid", 0);
|
||||
mFd = intent.getIntExtra("fd", 0);
|
||||
|
||||
final AlertController.AlertParams p = mAlertParams;
|
||||
p.mTitle = getString(R.string.log_access_confirmation_title);
|
||||
p.mView = createView();
|
||||
|
||||
p.mPositiveButtonText = getString(R.string.log_access_confirmation_allow);
|
||||
p.mPositiveButtonListener = this;
|
||||
p.mNegativeButtonText = getString(R.string.log_access_confirmation_deny);
|
||||
p.mNegativeButtonListener = this;
|
||||
|
||||
mAlert.installContent(mAlertParams);
|
||||
}
|
||||
|
||||
private View createView() {
|
||||
final View view = getLayoutInflater().inflate(R.layout.harmful_app_warning_dialog,
|
||||
null /*root*/);
|
||||
((TextView) view.findViewById(R.id.app_name_text))
|
||||
.setText(mPackageName);
|
||||
((TextView) view.findViewById(R.id.message))
|
||||
.setText(getIntent().getExtras().getString("body"));
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
switch (which) {
|
||||
case DialogInterface.BUTTON_POSITIVE:
|
||||
try {
|
||||
mLogcatManagerService.approve(mUid, mGid, mPid, mFd);
|
||||
} catch (Throwable t) {
|
||||
Slog.e(TAG, "Could not start the LogcatManagerService.", t);
|
||||
}
|
||||
finish();
|
||||
break;
|
||||
case DialogInterface.BUTTON_NEGATIVE:
|
||||
try {
|
||||
mLogcatManagerService.decline(mUid, mGid, mPid, mFd);
|
||||
} catch (Throwable t) {
|
||||
Slog.e(TAG, "Could not start the LogcatManagerService.", t);
|
||||
}
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the Intent for a LogAccessConfirmationActivity.
|
||||
*/
|
||||
public static Intent createIntent(Context context, String targetPackageName,
|
||||
IntentSender target, int uid, int gid, int pid, int fd) {
|
||||
final Intent intent = new Intent();
|
||||
intent.setClass(context, LogAccessConfirmationActivity.class);
|
||||
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
|
||||
intent.putExtra(EXTRA_UID, uid);
|
||||
intent.putExtra(EXTRA_GID, gid);
|
||||
intent.putExtra(EXTRA_PID, pid);
|
||||
intent.putExtra(EXTRA_FD, fd);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.logcat;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.os.logcat.ILogcatManagerService;
|
||||
import android.util.Slog;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
/**
|
||||
* Dialog responsible for obtaining user consent per-use log access
|
||||
*/
|
||||
public class LogAccessDialogActivity extends Activity implements
|
||||
View.OnClickListener {
|
||||
private static final String TAG = LogAccessDialogActivity.class.getSimpleName();
|
||||
private Context mContext;
|
||||
|
||||
private final ILogcatManagerService mLogcatManagerService =
|
||||
ILogcatManagerService.Stub.asInterface(ServiceManager.getService("logcat"));
|
||||
|
||||
private String mPackageName;
|
||||
|
||||
private int mUid;
|
||||
private int mGid;
|
||||
private int mPid;
|
||||
private int mFd;
|
||||
private String mAlertTitle;
|
||||
private AlertDialog.Builder mAlertDialog;
|
||||
private AlertDialog mAlert;
|
||||
|
||||
private static final int DIALOG_TIME_OUT = 300000;
|
||||
private static final int MSG_DISMISS_DIALOG = 0;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mContext = this;
|
||||
|
||||
Intent intent = getIntent();
|
||||
mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
|
||||
mUid = intent.getIntExtra("com.android.server.logcat.uid", 0);
|
||||
mGid = intent.getIntExtra("com.android.server.logcat.gid", 0);
|
||||
mPid = intent.getIntExtra("com.android.server.logcat.pid", 0);
|
||||
mFd = intent.getIntExtra("com.android.server.logcat.fd", 0);
|
||||
mAlertTitle = getTitleString(mContext, mPackageName, mUid);
|
||||
|
||||
if (mAlertTitle != null) {
|
||||
|
||||
mAlertDialog = new AlertDialog.Builder(this);
|
||||
mAlertDialog.setView(createView());
|
||||
|
||||
mAlert = mAlertDialog.create();
|
||||
mAlert.show();
|
||||
mHandler.sendEmptyMessageDelayed(MSG_DISMISS_DIALOG, DIALOG_TIME_OUT);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mAlert != null && mAlert.isShowing()) {
|
||||
mAlert.dismiss();
|
||||
}
|
||||
mAlert = null;
|
||||
}
|
||||
|
||||
private Handler mHandler = new Handler() {
|
||||
public void handleMessage(android.os.Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_DISMISS_DIALOG:
|
||||
if (mAlert != null) {
|
||||
mAlert.dismiss();
|
||||
mAlert = null;
|
||||
try {
|
||||
mLogcatManagerService.decline(mUid, mGid, mPid, mFd);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Fails to call remote functions", e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private String getTitleString(Context context, String callingPackage, int uid) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
try {
|
||||
return context.getString(
|
||||
com.android.internal.R.string.log_access_confirmation_title,
|
||||
pm.getApplicationInfoAsUser(callingPackage,
|
||||
PackageManager.MATCH_DIRECT_BOOT_AUTO,
|
||||
UserHandle.getUserId(uid)).loadLabel(pm));
|
||||
} catch (NameNotFoundException e) {
|
||||
Slog.e(TAG, "App name is unknown.", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private View createView() {
|
||||
final View view = getLayoutInflater().inflate(
|
||||
R.layout.log_access_user_consent_dialog_permission, null /*root*/);
|
||||
|
||||
((TextView) view.findViewById(R.id.log_access_dialog_title))
|
||||
.setText(mAlertTitle);
|
||||
|
||||
Button button_allow = (Button) view.findViewById(R.id.log_access_dialog_allow_button);
|
||||
button_allow.setOnClickListener(this);
|
||||
|
||||
Button button_deny = (Button) view.findViewById(R.id.log_access_dialog_deny_button);
|
||||
button_deny.setOnClickListener(this);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.log_access_dialog_allow_button:
|
||||
try {
|
||||
mLogcatManagerService.approve(mUid, mGid, mPid, mFd);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Fails to call remote functions", e);
|
||||
}
|
||||
finish();
|
||||
break;
|
||||
case R.id.log_access_dialog_deny_button:
|
||||
try {
|
||||
mLogcatManagerService.decline(mUid, mGid, mPid, mFd);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Fails to call remote functions", e);
|
||||
}
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,15 +18,12 @@ package com.android.server.logcat;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningAppProcessInfo;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.Binder;
|
||||
import android.os.ILogd;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
@@ -34,16 +31,14 @@ import android.os.UserHandle;
|
||||
import android.os.logcat.ILogcatManagerService;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.notification.SystemNotificationChannels;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
|
||||
/**
|
||||
* Service responsible for managing the access to Logcat.
|
||||
*/
|
||||
@@ -54,43 +49,16 @@ public final class LogcatManagerService extends SystemService {
|
||||
private final BinderService mBinderService;
|
||||
private final ExecutorService mThreadExecutor;
|
||||
private ILogd mLogdService;
|
||||
private NotificationManager mNotificationManager;
|
||||
private @NonNull ActivityManager mActivityManager;
|
||||
private ActivityManagerInternal mActivityManagerInternal;
|
||||
private static final int MAX_UID_IMPORTANCE_COUNT_LISTENER = 2;
|
||||
private static int sUidImportanceListenerCount = 0;
|
||||
private static final int AID_SHELL_UID = 2000;
|
||||
|
||||
// TODO This allowlist is just a temporary workaround for the tests:
|
||||
// FrameworksServicesTests
|
||||
// PlatformRuleTests
|
||||
// After adapting the test suites, the allowlist will be removed in
|
||||
// the upcoming bug fix patches.
|
||||
private static final String[] ALLOWABLE_TESTING_PACKAGES = {
|
||||
"android.platform.test.rule.tests",
|
||||
"com.android.frameworks.servicestests"
|
||||
};
|
||||
|
||||
// TODO Same as the above ALLOWABLE_TESTING_PACKAGES.
|
||||
private boolean isAllowableTestingPackage(int uid) {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
|
||||
String[] packageNames = pm.getPackagesForUid(uid);
|
||||
|
||||
if (ArrayUtils.isEmpty(packageNames)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String name : packageNames) {
|
||||
Slog.e(TAG, "isAllowableTestingPackage: " + name);
|
||||
|
||||
if (Arrays.asList(ALLOWABLE_TESTING_PACKAGES).contains(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
private static final String TARGET_PACKAGE_NAME = "android";
|
||||
private static final String TARGET_ACTIVITY_NAME =
|
||||
"com.android.server.logcat.LogAccessDialogActivity";
|
||||
private static final String EXTRA_UID = "com.android.server.logcat.uid";
|
||||
private static final String EXTRA_GID = "com.android.server.logcat.gid";
|
||||
private static final String EXTRA_PID = "com.android.server.logcat.pid";
|
||||
private static final String EXTRA_FD = "com.android.server.logcat.fd";
|
||||
|
||||
private final class BinderService extends ILogcatManagerService.Stub {
|
||||
@Override
|
||||
@@ -110,7 +78,7 @@ public final class LogcatManagerService extends SystemService {
|
||||
try {
|
||||
getLogdService().approve(uid, gid, pid, fd);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
Slog.e(TAG, "Fails to call remote functions", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +87,7 @@ public final class LogcatManagerService extends SystemService {
|
||||
try {
|
||||
getLogdService().decline(uid, gid, pid, fd);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
Slog.e(TAG, "Fails to call remote functions", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,46 +101,16 @@ public final class LogcatManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private String getBodyString(Context context, String callingPackage, int uid) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
try {
|
||||
return context.getString(
|
||||
com.android.internal.R.string.log_access_confirmation_body,
|
||||
pm.getApplicationInfoAsUser(callingPackage, PackageManager.MATCH_DIRECT_BOOT_AUTO,
|
||||
UserHandle.getUserId(uid)).loadLabel(pm));
|
||||
} catch (NameNotFoundException e) {
|
||||
// App name is unknown.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void sendNotification(int notificationId, String clientInfo, int uid, int gid, int pid,
|
||||
int fd) {
|
||||
|
||||
private void showDialog(int uid, int gid, int pid, int fd) {
|
||||
final ActivityManagerInternal activityManagerInternal =
|
||||
LocalServices.getService(ActivityManagerInternal.class);
|
||||
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
String packageName = activityManagerInternal.getPackageNameByPid(pid);
|
||||
if (packageName != null) {
|
||||
String notificationBody = getBodyString(mContext, packageName, uid);
|
||||
|
||||
final Intent mIntent = LogAccessConfirmationActivity.createIntent(mContext,
|
||||
packageName, null, uid, gid, pid, fd);
|
||||
|
||||
if (notificationBody == null) {
|
||||
// Decline the logd access if the nofitication body is unknown
|
||||
Slog.e(TAG, "Unknown notification body, declining the logd access");
|
||||
declineLogdAccess(uid, gid, pid, fd);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Next version will replace notification with dialogue
|
||||
// per UX guidance.
|
||||
generateNotificationWithBodyContent(notificationId, clientInfo, notificationBody,
|
||||
mIntent);
|
||||
Intent mIntent = createIntent(packageName, uid, gid, pid, fd);
|
||||
mContext.startActivityAsUser(mIntent, UserHandle.SYSTEM);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
String[] packageNames = pm.getPackagesForUid(uid);
|
||||
@@ -186,115 +124,28 @@ public final class LogcatManagerService extends SystemService {
|
||||
|
||||
String firstPackageName = packageNames[0];
|
||||
|
||||
if (firstPackageName == null || firstPackageName.length() == 0) {
|
||||
if (firstPackageName.isEmpty() || firstPackageName == null) {
|
||||
// Decline the logd access if the package name from uid is unknown
|
||||
Slog.e(TAG, "Unknown calling package name, declining the logd access");
|
||||
declineLogdAccess(uid, gid, pid, fd);
|
||||
return;
|
||||
}
|
||||
|
||||
String notificationBody = getBodyString(mContext, firstPackageName, uid);
|
||||
|
||||
final Intent mIntent = LogAccessConfirmationActivity.createIntent(mContext,
|
||||
firstPackageName, null, uid, gid, pid, fd);
|
||||
|
||||
if (notificationBody == null) {
|
||||
Slog.e(TAG, "Unknown notification body, declining the logd access");
|
||||
declineLogdAccess(uid, gid, pid, fd);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Next version will replace notification with dialogue
|
||||
// per UX guidance.
|
||||
generateNotificationWithBodyContent(notificationId, clientInfo,
|
||||
notificationBody, mIntent);
|
||||
final Intent mIntent = createIntent(firstPackageName, uid, gid, pid, fd);
|
||||
mContext.startActivityAsUser(mIntent, UserHandle.SYSTEM);
|
||||
}
|
||||
|
||||
private void declineLogdAccess(int uid, int gid, int pid, int fd) {
|
||||
try {
|
||||
getLogdService().decline(uid, gid, pid, fd);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.e(TAG, "Fails to call remote functions ", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateNotificationWithBodyContent(int notificationId, String clientInfo,
|
||||
String notificationBody, Intent intent) {
|
||||
final Notification.Builder notificationBuilder = new Notification.Builder(
|
||||
mContext,
|
||||
SystemNotificationChannels.ACCESSIBILITY_SECURITY_POLICY);
|
||||
intent.setFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
intent.setIdentifier(String.valueOf(notificationId) + clientInfo);
|
||||
intent.putExtra("body", notificationBody);
|
||||
|
||||
notificationBuilder
|
||||
.setSmallIcon(R.drawable.ic_info)
|
||||
.setContentTitle(
|
||||
mContext.getString(R.string.log_access_confirmation_title))
|
||||
.setContentText(notificationBody)
|
||||
.setContentIntent(
|
||||
PendingIntent.getActivity(mContext, 0, intent,
|
||||
PendingIntent.FLAG_IMMUTABLE))
|
||||
.setTicker(mContext.getString(R.string.log_access_confirmation_title))
|
||||
.setOnlyAlertOnce(true)
|
||||
.setAutoCancel(true);
|
||||
mNotificationManager.notify(notificationId, notificationBuilder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* A class which watches an uid for background access and notifies the logdMonitor when
|
||||
* the package status becomes foreground (importance change)
|
||||
*/
|
||||
private class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
|
||||
private final int mExpectedUid;
|
||||
private final int mExpectedGid;
|
||||
private final int mExpectedPid;
|
||||
private final int mExpectedFd;
|
||||
private int mExpectedImportance;
|
||||
private int mCurrentImportance = RunningAppProcessInfo.IMPORTANCE_GONE;
|
||||
|
||||
UidImportanceListener(int uid, int gid, int pid, int fd, int importance) {
|
||||
mExpectedUid = uid;
|
||||
mExpectedGid = gid;
|
||||
mExpectedPid = pid;
|
||||
mExpectedFd = fd;
|
||||
mExpectedImportance = importance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUidImportance(int uid, int importance) {
|
||||
if (uid == mExpectedUid) {
|
||||
mCurrentImportance = importance;
|
||||
|
||||
/**
|
||||
* 1) If the process status changes to foreground, send a notification
|
||||
* for user consent.
|
||||
* 2) If the process status remains background, we decline logd access request.
|
||||
**/
|
||||
if (importance <= RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) {
|
||||
String clientInfo = getClientInfo(uid, mExpectedGid, mExpectedPid, mExpectedFd);
|
||||
sendNotification(0, clientInfo, uid, mExpectedGid, mExpectedPid,
|
||||
mExpectedFd);
|
||||
mActivityManager.removeOnUidImportanceListener(this);
|
||||
|
||||
synchronized (LogcatManagerService.this) {
|
||||
sUidImportanceListenerCount--;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
getLogdService().decline(uid, mExpectedGid, mExpectedPid, mExpectedFd);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.e(TAG, "Fails to call remote functions ", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Fails to call remote functions", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getClientInfo(int uid, int gid, int pid, int fd) {
|
||||
return "UID=" + Integer.toString(uid) + " GID=" + Integer.toString(gid) + " PID="
|
||||
+ Integer.toString(pid) + " FD=" + Integer.toString(fd);
|
||||
+ Integer.toString(pid) + " FD=" + Integer.toString(fd);
|
||||
}
|
||||
|
||||
private class LogdMonitor implements Runnable {
|
||||
@@ -338,18 +189,22 @@ public final class LogcatManagerService extends SystemService {
|
||||
try {
|
||||
getLogdService().approve(mUid, mGid, mPid, mFd);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
Slog.e(TAG, "Fails to call remote functions", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Temporarily approve all the requests to unblock testing failures.
|
||||
try {
|
||||
getLogdService().approve(mUid, mGid, mPid, mFd);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
final int procState = mActivityManager.getUidImportance(Binder.getCallingUid());
|
||||
// If the process is foreground, send a notification for user consent
|
||||
if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
|
||||
showDialog(mUid, mGid, mPid, mFd);
|
||||
} else {
|
||||
/**
|
||||
* If the process is background, decline the logd access.
|
||||
**/
|
||||
declineLogdAccess(mUid, mGid, mPid, mFd);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,7 +215,6 @@ public final class LogcatManagerService extends SystemService {
|
||||
mBinderService = new BinderService();
|
||||
mThreadExecutor = Executors.newCachedThreadPool();
|
||||
mActivityManager = context.getSystemService(ActivityManager.class);
|
||||
mNotificationManager = mContext.getSystemService(NotificationManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -375,4 +229,23 @@ public final class LogcatManagerService extends SystemService {
|
||||
private void addLogdService() {
|
||||
mLogdService = ILogd.Stub.asInterface(ServiceManager.getService("logd"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the Intent for LogAccessDialogActivity.
|
||||
*/
|
||||
public Intent createIntent(String targetPackageName, int uid, int gid, int pid, int fd) {
|
||||
final Intent intent = new Intent();
|
||||
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
|
||||
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
|
||||
intent.putExtra(EXTRA_UID, uid);
|
||||
intent.putExtra(EXTRA_GID, gid);
|
||||
intent.putExtra(EXTRA_PID, pid);
|
||||
intent.putExtra(EXTRA_FD, fd);
|
||||
|
||||
intent.setComponent(new ComponentName(TARGET_PACKAGE_NAME, TARGET_ACTIVITY_NAME));
|
||||
|
||||
return intent;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user