blob: 98bae3dc247b4ea6cfbbe464bf22d3e6817c22b9 [file] [log] [blame]
/*
* 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.annotation.StyleRes;
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.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.util.Slog;
import android.view.ContextThemeWrapper;
import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.android.internal.R;
import com.android.server.LocalServices;
/**
* 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 static final int DIALOG_TIME_OUT = Build.IS_DEBUGGABLE ? 60000 : 300000;
private static final int MSG_DISMISS_DIALOG = 0;
private final LogcatManagerService.LogcatManagerServiceInternal mLogcatManagerInternal =
LocalServices.getService(LogcatManagerService.LogcatManagerServiceInternal.class);
private String mPackageName;
private int mUid;
private String mAlertTitle;
private AlertDialog.Builder mAlertDialog;
private AlertDialog mAlert;
private View mAlertView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retrieve Intent extra information
if (!readIntentInfo(getIntent())) {
Slog.e(TAG, "Invalid Intent extras, finishing");
finish();
return;
}
// retrieve the title string from passed intent extra
try {
mAlertTitle = getTitleString(this, mPackageName, mUid);
} catch (NameNotFoundException e) {
Slog.e(TAG, "Unable to fetch label of package " + mPackageName, e);
declineLogAccess();
finish();
return;
}
// create View
boolean isDarkTheme = (getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
int themeId = isDarkTheme ? android.R.style.Theme_DeviceDefault_Dialog_Alert :
android.R.style.Theme_DeviceDefault_Light_Dialog_Alert;
mAlertView = createView(themeId);
// create AlertDialog
mAlertDialog = new AlertDialog.Builder(this, themeId);
mAlertDialog.setView(mAlertView);
mAlertDialog.setOnCancelListener(dialog -> declineLogAccess());
mAlertDialog.setOnDismissListener(dialog -> finish());
// show Alert
mAlert = mAlertDialog.create();
mAlert.show();
// set Alert Timeout
mHandler.sendEmptyMessageDelayed(MSG_DISMISS_DIALOG, DIALOG_TIME_OUT);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!isChangingConfigurations() && mAlert != null && mAlert.isShowing()) {
mAlert.dismiss();
}
mAlert = null;
}
private boolean readIntentInfo(Intent intent) {
if (intent == null) {
Slog.e(TAG, "Intent is null");
return false;
}
mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
if (mPackageName == null || mPackageName.length() == 0) {
Slog.e(TAG, "Missing package name extra");
return false;
}
if (!intent.hasExtra(Intent.EXTRA_UID)) {
Slog.e(TAG, "Missing EXTRA_UID");
return false;
}
mUid = intent.getIntExtra(Intent.EXTRA_UID, 0);
return true;
}
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;
declineLogAccess();
}
break;
default:
break;
}
}
};
private String getTitleString(Context context, String callingPackage, int uid)
throws NameNotFoundException {
PackageManager pm = context.getPackageManager();
CharSequence appLabel = pm.getApplicationInfoAsUser(callingPackage,
PackageManager.MATCH_DIRECT_BOOT_AUTO,
UserHandle.getUserId(uid)).loadLabel(pm);
String titleString = context.getString(
com.android.internal.R.string.log_access_confirmation_title, appLabel);
return titleString;
}
/**
* Returns the dialog view.
* If we cannot retrieve the package name, it returns null and we decline the full device log
* access
*/
private View createView(@StyleRes int themeId) {
Context themedContext = new ContextThemeWrapper(getApplicationContext(), themeId);
final View view = LayoutInflater.from(themedContext).inflate(
R.layout.log_access_user_consent_dialog_permission, null /*root*/);
if (view == null) {
throw new InflateException();
}
((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:
mLogcatManagerInternal.approveAccessForClient(mUid, mPackageName);
finish();
break;
case R.id.log_access_dialog_deny_button:
declineLogAccess();
finish();
break;
}
}
private void declineLogAccess() {
mLogcatManagerInternal.declineAccessForClient(mUid, mPackageName);
}
}